文章插图
环境:springboot2.5.12
经常会遇到在项目中调用第三方接口的情景,你是如何调用的呢?同步?异步?
场景:
假设下单业务流程如下步骤:
1、查询用户信息 。
2、查询库存信息 。
3、查询活动信息(折扣) 。
1、同步顺序调用
public boolean createOrder() {long start = System.currentTimeMillis() ;String userResult = restTemplate.getForObject("http://localhost:8080/users/{1}", String.class, new Object[] {1}) ;String storageResult = restTemplate.getForObject("http://localhost:8080/storage/{1}", String.class, new Object[] {1}) ;String discountResult = restTemplate.getForObject("http://localhost:8080/discount/{1}", String.class, new Object[] {1}) ;// 这里合并请求结果处理System.out.println(Arrays.toString(new String[] {userResult, storageResult, discountResult})) ;System.out.println("传统方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;return true ;}@GetMApping("/create")public Object create() {return os.createOrder() ;}
调用结果:文章插图
图片
接口一个一个调用,非常耗时 。
2、多线程(Callable+Future)
public boolean createOrder2() {long start = System.currentTimeMillis() ;Callable<String> userCallable = () -> {return restTemplate.getForObject("http://localhost:8080/users/{1}", String.class, new Object[] {1}) ;} ;Callable<String> storageCallable = () -> {return restTemplate.getForObject("http://localhost:8080/storage/{1}", String.class, new Object[] {1}) ;} ;Callable<String> discountCallable = () -> {return restTemplate.getForObject("http://localhost:8080/discount/{1}", String.class, new Object[] {1}) ;} ;FutureTask<String> userTask = new FutureTask<>(userCallable) ;FutureTask<String> storageTask = new FutureTask<>(storageCallable) ;FutureTask<String> discountTask = new FutureTask<>(discountCallable) ;new Thread(userTask).start() ;new Thread(storageTask).start() ;new Thread(discountTask).start() ;try {String userResult = userTask.get() ;String storageResult = storageTask.get() ;String discountResult = discountTask.get() ;// 这里合并请求结果处理System.out.println(Arrays.toString(new String[] {userResult, storageResult, discountResult})) ;} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}System.out.println("多线程方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;return true ;}
调用结果:文章插图
图片
这次耗时少了,性能明显提升了 。但在项目中我们一般是禁止直接创建线程的,如果这是个高并发的接口,那么我们的程序很可能出现OOM的错误 。
3、线程池(Callable+Future)防止内存溢出风险
ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000)) ;public boolean createOrder3() {long start = System.currentTimeMillis() ;List<Future<String>> results = new ArrayList<>(3) ;results.add(pool.submit(() -> {return restTemplate.getForObject("http://localhost:8080/users/{1}", String.class, new Object[] {1}) ;})) ;results.add(pool.submit(() -> {return restTemplate.getForObject("http://localhost:8080/storage/{1}", String.class, new Object[] {1}) ;})) ;results.add(pool.submit(() -> {return restTemplate.getForObject("http://localhost:8080/discount/{1}", String.class, new Object[] {1}) ;})) ;for (int i = 0, size = results.size(); i < size; i++) {try {System.out.println(results.get(i).get()) ;} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}System.out.println("线程池方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;return true ;}
调用结果:文章插图
图片
耗时和上一个基本一致,通过Future的方式有一个问题就是只能一个一个的取值,只有当前的返回数据了后才会继续往下执行 。如果有其它的任务执行完,那没有轮到它也必须等待 。
4、CompletionService(异步任务与使用已完成任务的结果分离),submit提交任务,take获取已经完成的任务,不用按照submit的顺序获取结果 。
public boolean createOrder4() {long start = System.currentTimeMillis() ;CompletionService<String> cs = new ExecutorCompletionService<>(pool) ;cs.submit(() -> {return restTemplate.getForObject("http://localhost:8080/users/{1}", String.class, new Object[] {1}) ;}) ;cs.submit(() -> {return restTemplate.getForObject("http://localhost:8080/storage/{1}", String.class, new Object[] {1}) ;}) ;cs.submit(() -> {return restTemplate.getForObject("http://localhost:8080/discount/{1}", String.class, new Object[] {1}) ;}) ;for (int i = 2 ; i >=0; i--) {try {System.out.println(cs.take().get()) ;} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}System.out.println("CompletionService方式耗时:" + (System.currentTimeMillis() - start) + "毫秒") ;return true ;}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Kubernetes 1.28发布,包含45项增强功能!
- 车险保什么 车险保什么项目最合算
- 羽绒服的洗涤方法及注意事项 羽绒服的洗涤方法
- 多肉养殖方法及注意事项 多肉养殖方法大全
- 玉树的养殖方法和注意事项玉树的栽培技术 玉树的养殖方法和注意事项是什么
- 新房购买流程及注意事项 房贷做不下来,能退首付吗
- 拼车包车注意事项和细节 拼车包车注意事项
- word怎么添加项目符号 word怎么添加项目符号双引号
- 请教别人的注意事项有哪些 请教别人的注意事项
- 前台服务的注意事项 前台服务要点