ThreadPoolExecutor 除了execute 方法用來提交任務(wù)自阱,還有submit 方法,他們的區(qū)別就是后者有返回值米酬,其原理是在前者的基礎(chǔ)上使用了Future 接口沛豌。因此,我之前的示例改用submit 方法來實現(xiàn)會更加簡單淮逻。原因有二:
1琼懊、submit 方法提交的任務(wù)有返回值,方便判斷每個任務(wù)的最終運(yùn)行結(jié)果爬早,無需引入狀態(tài)標(biāo)識變量
2哼丈、future 的get方法是阻塞的,無需引入CountDownLatch 并發(fā)包工具也可以等待所有線程運(yùn)行完畢
直接上代碼
package com.yzy.test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class Main2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 線程安全的計數(shù)器
AtomicInteger totalRows = new AtomicInteger(0);
// 創(chuàng)建線程池筛严,其中核心線程10醉旦,也是我期望的最大并發(fā)數(shù),最大線程數(shù)和隊列大小都為30桨啃,即我的總?cè)蝿?wù)數(shù)
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 30, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(30));
// 創(chuàng)建 Future 集合车胡,用來存儲Future 實例
List<Future<Integer>> futureList = new ArrayList<>();
for (int i = 0; i < 30; i++) {
final int index = i;
// 這里創(chuàng)建 Callable 實例,返回整型
Future<Integer> future = executor.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
// 模擬異常的線程照瘾,返回0
if (index % 5 == 0) {
return 0;
}
int times = 0;
boolean loop = true;
// 模擬數(shù)據(jù)拉取過程可能需要分頁
while (loop) {
// 模擬每個任務(wù)需要分頁5次
if (times >= 5) {
break;
}
times++;
// 模擬計數(shù)
totalRows.incrementAndGet();
// 模擬耗時
try {
// 打印運(yùn)行情況
System.out.println(Thread.currentThread().getName() + ":" + index + ":" + times);
Thread.sleep(Long.valueOf(String.valueOf(new Double(Math.random() * 1000).intValue())));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 成功返回1
return 1;
}
});
futureList.add(future);
}
// 標(biāo)記多線程關(guān)閉匈棘,但不會立馬關(guān)閉
executor.shutdown();
boolean flag = true;
for (Future<Integer> future : futureList) {
// 獲取每一個線程的返回結(jié)果,如果該線程未完成析命,會阻塞
if (future.get() == 0) {
flag = false;
}
}
if (flag) {
System.out.println("全部成功了,計數(shù):" + totalRows.get());
} else {
System.out.println("失敗了");
}
}
}
運(yùn)行結(jié)果:
//省略若干行
pool-1-thread-7:24:5
pool-1-thread-3:29:3
pool-1-thread-3:29:4
pool-1-thread-5:28:3
pool-1-thread-6:26:4
pool-1-thread-6:26:5
pool-1-thread-5:28:4
pool-1-thread-5:28:5
pool-1-thread-3:29:5
失敗了
然后注釋這部分代碼
if (index % 5 == 0) {
return 0;
}
再次運(yùn)行:
//省略若干行
pool-1-thread-7:24:4
pool-1-thread-7:24:5
pool-1-thread-1:26:5
pool-1-thread-8:25:4
pool-1-thread-8:25:5
pool-1-thread-3:29:4
pool-1-thread-3:29:5
全部成功了,計數(shù):150