使用java多线程来优化多次串行查询

示例代码:https://gitee.com/constfafa/imooc-zookeeper-starter下的searchcountdown package

背景:

spring boot web项目

controller要调用同一个service下的4个服务

目前采用的是串行方式

String items = esService.searchQueryItems("xxx");
String guides = esService.searchQueryGuides("xxx");
String applications = esService.getApplications("xxx");
String appoints = esService.getAppointItems("xxx");

 

示例代码App

 

item耗时3秒 guides耗时1秒 applications耗时1秒 appoints耗时1秒

 

共耗时6001ms

[xxx items, xxx guides, xxx applications, xxx appointments]

 

这样很耗时,如何用多线程来优化呢?

 

尝试1:使用CountDownLatch

示例代码App3

 

思路是使用threadpoolExecutor,启动4个线程分别执行

在主线程中用countDownLatch.await();来等待执行完成

 

结果:3048

[changliang guides, changliang appointments, changliang applications, changliang items]

 

可见这种方式是并行执行的,耗时时间取决于并行执行耗时最长的

但这种方式有一个不足:

如果我有一个接口特别慢,比如items特别慢,30秒,那么也是要执行30秒才会返回的,应该要对时间进行控制

 

尝试2:使用FutureTask

示例代码App4

 

参考:java 方法超过执行时间后抛出异常

思路:

先创建4个FutureTask

通过threadpoolexecutor启动4个线程来执行

然后通过

FutureTask.get(2, TimeUnit.SECONDS)

来控制访问时间,异步获取返回值

 

结果:

2151

[changliang guides, changliang applications, changliang appointments]

java.lang.reflect.InvocationTargetException

         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

         at java.lang.reflect.Method.invoke(Method.java:498)

         at com.imooc.searchcountdown.App4.lambda$main$0(App4.java:45)

         at java.util.concurrent.FutureTask.run(FutureTask.java:266)

         at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

         at java.lang.Thread.run(Thread.java:745)

Caused by: java.lang.InterruptedException: sleep interrupted

         at java.lang.Thread.sleep(Native Method)

         at com.imooc.searchcountdown.EsService.searchQueryItems(EsService.java:10)

         ... 9 more

 

可见这种方式是我们期望的方式

不足:这种方式作为demo程序是可以的,但是如果生产中使用是并不合适的,因为每一次都要新创建线程池,启动4个线程,执行完成,再关闭线程池。

 

尝试3:FutureTask + 单例ThreadpoolExecutor

示例代码App5

达到我们希望的效果了

猜你喜欢

转载自blog.csdn.net/u013905744/article/details/88247889