Java 監控線程池所有任務是否執行完畢
場景引入
在最近的工作中遇到一個需要批量生產百萬數據並寫入數據庫的需求,先通過單線程的方式去實現,但是感覺效率一般,然後通過多線程的方式去改進,但是遇到下面的問題:
生成數據的時候,每生成一條數據,就將數據丟入到集合中進行緩存,當集合中的數據量達到 500 的時候,就進行一次數據庫寫入操作,並清空集合。
那麼當我生成的數據量爲 1200 的時候,就會出現最後 200 條沒有寫入到數據庫的問題
那麼要解決這個問題,就要知道線程池的任務什麼時候執行完畢,網上找了很多方法如:
- 方案一 - 直接調用是否終止的方法
executor.isTerminated()
- 方案二 - 判斷活躍線程數
executor.getActiveCount() == 0
- 方案三 - 設置一個較長的等待時間
executor.awaitTermination(10000, TimeUnit.SECONDS);
但是都沒有達到我的目的(也有可能是我使用的姿勢不對)
最後嘗試了下面的方法
功能實現
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
@Slf4j
public class ThreadPoolTest {
static List<Integer> TEMP_LIST = new ArrayList<>(10);
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
Random random = new Random();
int count = random.nextInt(100);
for (int i = 0; i < count; i++) {
int finalI = i;
executorService.execute(() -> {
addToTemp(finalI * 2, false);
try {
Thread.sleep(random.nextInt(1000 * 2));
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 監控線程執行情況
monitor((ThreadPoolExecutor) executorService);
// 最後一次數據插入
addToTemp(null, true);
System.out.println("結束");
}
/**
* 添加數據到緩存
*
* @Author: Neo
* @Date: 2019/12/19 21:46
* @Version: 1.0
*/
public static synchronized void addToTemp(Integer data, boolean focus) {
if (null != data) {
TEMP_LIST.add(data);
}
if (CollectionUtils.isNotEmpty(TEMP_LIST) && (CollectionUtils.size(TEMP_LIST) >= 10 || focus)) {
// 模擬數據庫寫入
log.info("執行一次插入,數據量:{}", CollectionUtils.size(TEMP_LIST));
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
TEMP_LIST.clear();
}
}
/**
* 監控線程執行情況
* 一直阻塞到線程任務執行完畢
*
* @Author: Neo
* @Date: 2019/12/19 21:09
* @Version: 1.0
*/
public static void monitor(ThreadPoolExecutor executor) {
while (!isTerminated(executor)) {
try {
int queueSize = executor.getQueue().size();
int activeCount = executor.getActiveCount();
long completedTaskCount = executor.getCompletedTaskCount();
long taskCount = executor.getTaskCount();
log.info("當前排隊線程數:{},當前活動線程數:{},執行完成線程數:{},總線程數:{}", queueSize, activeCount, completedTaskCount, taskCount);
Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 線程池任務是否執行完畢
*
* @Author: Neo
* @Date: 2019/12/19 21:11
* @Version: 1.0
*/
public static boolean isTerminated(ThreadPoolExecutor executor) {
return executor.getQueue().size() == 0 && executor.getActiveCount() == 0;
}
}