SpringBoot项目中异步调用接口方式知多少?

2025-05-27 0 93

SpringBoot项目中异步调用接口方式知多少?

环境: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)+"毫秒");

returntrue;

}

@GetMapping("/create")

publicObjectcreate(){

returnos.createOrder();

}

调用结果:

SpringBoot项目中异步调用接口方式知多少?

接口一个一个调用,非常耗时。

2.多线程(Callable+Future)

publicbooleancreateOrder2(){

longstart=System.currentTimeMillis();

Callable<String>userCallable=()->{

returnrestTemplate.getForObject("http://localhost:8080/users/{1}",String.class,newObject[]{1});

};

Callable<String>storageCallable=()->{

returnrestTemplate.getForObject("http://localhost:8080/storage/{1}",String.class,newObject[]{1});

};

Callable<String>discountCallable=()->{

returnrestTemplate.getForObject("http://localhost:8080/discount/{1}",String.class,newObject[]{1});

};

FutureTask<String>userTask=newFutureTask<>(userCallable);

FutureTask<String>storageTask=newFutureTask<>(storageCallable);

FutureTask<String>discountTask=newFutureTask<>(discountCallable);

newThread(userTask).start();

newThread(storageTask).start();

newThread(discountTask).start();

try{

StringuserResult=userTask.get();

StringstorageResult=storageTask.get();

StringdiscountResult=discountTask.get();

//这里合并请求结果处理

System.out.println(Arrays.toString(newString[]{userResult,storageResult,discountResult}));

}catch(InterruptedException|ExecutionExceptione){

e.printStackTrace();

}

System.out.println("多线程方式耗时:"+(System.currentTimeMillis()-start)+"毫秒");

returntrue;

}

调用结果:

SpringBoot项目中异步调用接口方式知多少?

这次耗时少了,性能明显提升了。但在项目中我们一般是禁止直接创建线程的,如果这是个高并发的接口,那么我们的程序很可能出现OOM的错误。

3.线程池(Callable+Future)防止内存溢出风险

ThreadPoolExecutorpool=newThreadPoolExecutor(5,5,60,TimeUnit.SECONDS,newArrayBlockingQueue<Runnable>(1000));

publicbooleancreateOrder3(){

longstart=System.currentTimeMillis();

List<Future<String>>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();i<size;i++){

try{

System.out.println(results.get(i).get());

}catch(InterruptedException|ExecutionExceptione){

e.printStackTrace();

}

}

System.out.println("线程池方式耗时:"+(System.currentTimeMillis()-start)+"毫秒");

returntrue;

}

调用结果:

SpringBoot项目中异步调用接口方式知多少?

耗时和上一个基本一致,通过Future的方式有一个问题就是只能一个一个的取值,只有当前的返回数据了后才会继续往下执行。如果有其它的任务执行完,那没有轮到它也必须等待。

4.CompletionService(异步任务与使用已完成任务的结果分离),submit提交任务,take获取已经完成的任务,不用按照submit的顺序获取结果。

publicbooleancreateOrder4(){

longstart=System.currentTimeMillis();

CompletionService<String>cs=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;

}

调用结果:

SpringBoot项目中异步调用接口方式知多少?

通过CompletionService方式不管任务添加的顺序是什么,只要通过take方法就能获取执行完的结果,如果没有任务执行完,take方法会阻塞。

5.CompletableFuture(异步任务编排),JDK1.8

publicbooleancreateOrder5(){

longstart=System.currentTimeMillis();

CompletableFuture<String>userFuture=CompletableFuture.supplyAsync(()->{

returnrestTemplate.getForObject("http://localhost:8080/users/{1}",String.class,newObject[]{1});

});

CompletableFuture<String>storageFuture=CompletableFuture.supplyAsync(()->{

returnrestTemplate.getForObject("http://localhost:8080/storage/{1}",String.class,newObject[]{1});

});

CompletableFuture<String>discountFuture=CompletableFuture.supplyAsync(()->{

returnrestTemplate.getForObject("http://localhost:8080/discount/{1}",String.class,newObject[]{1});

});

CompletableFuture<List<String>>result=CompletableFuture

.allOf(userFuture,storageFuture,discountFuture)

.thenApply((Void)->{

List<String>datas=newArrayList<>();

try{

datas.add(userFuture.get());

datas.add(storageFuture.get());

datas.add(discountFuture.get());

}catch(InterruptedException|ExecutionExceptione){

e.printStackTrace();

}

returndatas;

}).exceptionally(e->{

e.printStackTrace();

returnnull;

});

try{

System.out.println(result.get());

}catch(InterruptedException|ExecutionExceptione1){

e1.printStackTrace();

}

System.out.println("CompletableFuture方式耗时:"+(System.currentTimeMillis()-start)+"毫秒");

returntrue;

}

调用结果:

SpringBoot项目中异步调用接口方式知多少?

CompletableFuture提供了非常强大的异步编程方法,可同步,可异步,可编排任务执行,异步通过回调的方式执行。该对象很多的一些方法与前端JavaScript中的Promise对象有点相像。

原文地址:https://www.toutiao.com/i6940533670621217316/

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 SpringBoot项目中异步调用接口方式知多少? https://www.kuaiidc.com/76494.html

相关文章

发表评论
暂无评论