示例代码: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
思路:
先创建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
达到我们希望的效果了