当前位置: 首页 > 科技观察

SpringBoot项目中的异步调用接口方法你了解多少?

时间:2023-03-16 16:09:05 科技观察

环境:springboot2.3.9.RELEASE在项目中经常会遇到调用第三方接口的场景。你怎么称呼它?同步?异步?场景:假设下单的业务流程如下:1.查询用户信息。2.查询库存信息。3.查询活动信息(折扣)。1.在调用publicbooleancreateOrder(){longstart=System.currentTimeMillis();StringuserResult=restTemplate.getForObject("http://localhost:8080/users/{1}",String.class,newObject[]{1})同步顺序;StringstorageResult=restTemplate.getForObject("http://localhost:8080/storage/{1}",String.class,newObject[]{1});StringdiscountResult=restTemplate.getForObject("http://localhost:8080/discount/{1}",String.class,newObject[]{1});//这里合并请求结果处理System.out.println(Arrays.toString(newString[]{userResult,storageResult,discountResult}));System.out.println("传统耗时:"+(System.currentTimeMillis()-start)+"milliseconds");returntrue;}@GetMapping("/create")publicObjectcreate(){returnos.createOrder();}调用结果:接口一个一个调用,非常耗时。2.多线程序(Callable+Future)publicbooleancreateOrder2(){longstart=System.currentTimeMillis();CallableuserCallable=()->{returnrestTemplate.getForObject("http://localhost:8080/users/{1}",String.class,newObject[]{1});};CallablestorageCallable=()->{returnrestTemplate.getForObject("http://localhost:8080/storage/{1}",String.class,newObject[]{1});};CallablediscountCallable=()->{returnrestTemplate.getForObject("http://localhost:8080/discount/{1}",String.class,newObject[]{1});};FutureTaskuserTask=newFutureTask<>(userCallable);FutureTaskstorageTask=newFutureTask<>(storageCallable);FutureTaskdiscountTask=newFutureTask<>(discountCallable);newThread(userTask)。start();newThread(storageTask).start();newThread(discountTask).start();try{StringuserResult=userTask.get();StringstorageResult=storageTask.get();StringdiscountResult=discountTask.get();//这里合并请求结果处理}System.out.println("多线程耗时:"+(System.currentTimeMillis()-start)+"毫秒");returntrue;}调用结果:这次耗时少了,性能明显提升。但是在项目中,我们一般禁止直接创建线程。如果这是一个高并发的接口,那么我们的程序很可能会出现OOM错误。3.线程池(Callable+Future)防止内存溢出风险ThreadPoolExecutorpool=newThreadPoolExecutor(5,5,60,TimeUnit.SECONDS,newArrayBlockingQueue(1000));publicbooleancreateOrder3(){longstart=System.currentTimeMillis();List>results=newArrayList<>(3);results.add(pool.submit(()->{returnrestTemplate.getForObject("http://localhost:8080/users/{1}",String.class,newObject[]{1});}));results.add(pool.submit(()->{returnrestTemplate.getForObject("http://localhost:8080/storage/{1}",String.class,newObject[]{1});}));results.add(pool.submit(()->{returnrestTemplate.getForObject("http://localhost:8080/discount/{1}",String.class,newObject[]{1});}));for(inti=0,size=results.size();ics=newExecutorCompletionService<>(pool);cs.submit(()->{returnrestTemplate.getForObject("http://localhost:8080/users/{1}",String.class,newObject[]{1});});cs.submit(()->{returnrestTemplate.getForObject("http://localhost:8080/storage/{1}",String.class,newObject[]{1});});cs.submit(()->{returnrestTemplate.getForObject("http://localhost:8080/discount/{1}",String.class,newObject[]{1});});for(inti=2;i>=0;i--){try{System.out.println(cs.take().get());}catch(InterruptedException|ExecutionExceptione){e.printStackTrace();}}System.out.println("CompletionService耗时:"+(System.currentTimeMillis()-start)+"毫秒");returntrue;}调用结果:不管CompletionService添加任务的顺序是什么,只要能通过take方法获取到执行结果,如果没有任务完成,take方法就会阻塞。5.CompletableFuture(异步任务编排),JDK1.8publicbooleancreateOrder5(){longstart=System.currentTimeMillis();CompletableFutureuserFuture=CompletableFuture.supplyAsync(()->{returnrestTemplate.getForObject("http://localhost:8080/users/{1}",String.class,newObject[]{1});});CompletableFuturestorageFuture=CompletableFuture.supplyAsync(()->{returnrestTemplate.getForObject("http://localhost:8080/storage/{1}",String.class,newObject[]{1});});CompletableFuturediscountFuture=CompletableFuture.supplyAsync(()->{returnrestTemplate.getForObject("http://localhost:8080/discount/{1}",String.class,newObject[]{1});});CompletableFuture>result=CompletableFuture.allOf(userFuture,storageFuture,discountFuture).thenApply((Void)->{Listdatas=newArrayList<>();try{datas.add(userFuture.get());datas.add(storageFuture.get());datas.add(discountFuture.get());}catch(InterruptedException|ExecutionExceptione){e.printStackTrace();}returndatas;}).exceptionally(e->{e.printStackTrace();returnull;});try{System.out.println(result.get());}catch(InterruptedException|ExecutionExceptione1){e1.printStackTrace();}System.out.println("CompletableFuture耗时:"+(System.currentTimeMillis()-start)+"毫秒");returntrue;}调用结果:CompletableFuture提供了一个非常强大的异步编程方法,可以同步,也可以异步,可以安排任务执行。通过回调异步执行这个对象的一些方法有点类似于前端JavaScript中的Promise对象。