問題描述
記錄下一次代碼評審的問題點,發(fā)現(xiàn)這個也是自己以前犯過的內(nèi)容.在使用多線程情況下,查看日志發(fā)現(xiàn)似乎還是單線程在跑的效果
問題案例
先看下面的代碼
@Slf4j
public class ThreadPoolTest2 {
private static ThreadPoolExecutor testThreadPool = new ThreadPoolExecutor(10, 10, 180L,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), new CustomizableThreadFactory("test-pool-"), new ThreadPoolExecutor.CallerRunsPolicy());
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
handlerA();
log.info("耗時->{}ms", System.currentTimeMillis() - startTime);
}
private static void handlerA() {
for (int i = 0; i < 100; i++) {
String param = i + "";
Future<String> resultFuture = testThreadPool.submit(() -> getResult(param));
String result = null;
try {
result = resultFuture.get();
} catch (Exception e) {
e.printStackTrace();
}
log.info("handlerA future get,result->{}", result);
}
}
private static String getResult(String i) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
String result = "result-" + i;
log.info("result->{}", result);
return result;
}
}
查看日志,可以看到是有不同的線程在跑任務,但效果就是單線程的效果.耗時也是單線程情況下的耗時
image.png
問題分析以及解決方案
先看下下面修改后的代碼,對比下
private static void handlerB() {
List<Future<String>> futureList = new ArrayList<>();
for (int i = 0; i < 30; i++) {
String param = i + "";
Future<String> resultFuture = testThreadPool.submit(() -> getResult(param));
futureList.add(resultFuture);
}
for (Future<String> resultFuture : futureList) {
String result = null;
try {
result = resultFuture.get();
} catch (Exception e) {
e.printStackTrace();
}
log.info("handlerB future get,result->{}", result);
}
}
先看下效果(可以看到這個才是自己想要的多線程的效果)
image.png
原因分析
其實對比下代碼,可以發(fā)現(xiàn),在main線程遍歷過程中使用future.get().這個急阻塞main線程等到線程完成任務.這樣其實就和單線程是同樣的效果了
在優(yōu)化后的handlerB中,main線程優(yōu)先使用線程跑任務,最終才使用main從future列表里等待線程任務結(jié)束.