面試官:如何確保動(dòng)態(tài)線程池任務(wù)都執(zhí)行完?
在 Java 并發(fā)編程中,線程池是提高系統(tǒng)吞吐量和響應(yīng)速度的重要工具。
而是在高并發(fā)場(chǎng)景下,動(dòng)態(tài)線程池(程序運(yùn)行期間動(dòng)態(tài)調(diào)整線程池參數(shù)而無需重啟程序的技術(shù))被廣泛應(yīng)用。然而,如何確保動(dòng)態(tài)線程池中的所有任務(wù)都執(zhí)行完畢,是一個(gè)常見的面試問題,也是實(shí)際開發(fā)中必須解決的關(guān)鍵問題。
所以,本文將深入探討幾種常見的方法,幫助開發(fā)者在實(shí)際項(xiàng)目中優(yōu)雅地處理這個(gè)問題。
方法一:CountDownLatch
使用 CountDownLatch 來跟蹤任務(wù)的完成情況,實(shí)現(xiàn)代碼如下:
// 動(dòng)態(tài)線程池
@Autowired
@Qualifier("dtpExecutor1")
private DtpExecutor dtpExecutor;
@RequestMapping("isDone")
public String isDone() throws InterruptedException {
    // 申請(qǐng)計(jì)數(shù)器
    CountDownLatch latch = new CountDownLatch(10);
    for (int i = 0; i < 10; i++) {
        dtpExecutor.submit(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("Task executed by " + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                latch.countDown(); // 任務(wù)完成,計(jì)數(shù)器減1
            }
        });
    }
    // 等待所有任務(wù)完成
    latch.await();
    return"ok";
}關(guān)鍵點(diǎn):
- CountDownLatch:初始化時(shí)指定任務(wù)數(shù)量。每個(gè)任務(wù)完成后調(diào)用 countDown(),主線程調(diào)用 await() 等待所有任務(wù)完成。
 - 適用場(chǎng)景:適用于需要精確控制任務(wù)完成狀態(tài)的場(chǎng)景,比如批處理任務(wù)、數(shù)據(jù)聚合等。
 
注意:CountDownLatch 是一次性的,不能重復(fù)使用;如果需要重復(fù)使用,可以考慮 CyclicBarrier。
方法二:CompletableFuture
從 Java 8 開始,CompletableFuture 提供了更強(qiáng)大的異步編程能力。它不僅支持 Future 的功能,還支持任務(wù)編排、組合、異常處理等高級(jí)特性。使用 CompletableFuture,可以更方便地管理多個(gè)異步任務(wù)的執(zhí)行,并確保所有任務(wù)都完成。
我們可以借助 CompletableFuture 提供了 allOf() 方法,可以等待所有任務(wù)完成,具體實(shí)現(xiàn)代碼如下:
// 動(dòng)態(tài)線程池
@Autowired
@Qualifier("dtpExecutor1")
private DtpExecutor dtpExecutor;
@RequestMapping("isDone")
public String isDone() {
    // 1.任務(wù)一
    CompletableFuture future = CompletableFuture.runAsync(() -> {
        // 執(zhí)行業(yè)務(wù)邏輯
    }, dtpExecutor);
    // 2.任務(wù)二
    CompletableFuture future2 = CompletableFuture.runAsync(() -> {
        // 執(zhí)行業(yè)務(wù)邏輯
    }, dtpExecutor);
    // 等待所有任務(wù)完成
    CompletableFuture<Void> allTask = CompletableFuture.allOf(future, future2);
    // 阻塞直到全部完成(無需結(jié)果)
    allTask.join();
    return"ok";
}關(guān)鍵點(diǎn):
- CompletableFuture.runAsync() :異步執(zhí)行任務(wù),無任何返回值。指定動(dòng)態(tài)線程池,避免使用默認(rèn)的 ForkJoinPool。
 - allOf() :等待所有任務(wù)完成。返回一個(gè) CompletableFuture,調(diào)用 join() 或 get() 會(huì)阻塞,直到所有任務(wù)完成。
 - join() :類似于 get(),但不會(huì)拋出檢查異常,更適合在流式操作中使用。
 
小結(jié)
確保動(dòng)態(tài)線程池中的所有任務(wù)都執(zhí)行完畢,本文介紹了兩種常見的方法:
- CountDownLatch:適用于需要精確控制任務(wù)完成狀態(tài)的場(chǎng)景。
 - CompletableFuture:適用于復(fù)雜異步任務(wù)編排、批量任務(wù)管理、異常處理和超時(shí)控制。
 
最后:面試官問這個(gè)問題,避免回答過于八股化和 AI 化。因此,在回答時(shí),可以結(jié)合自己的具體項(xiàng)目模塊實(shí)現(xiàn)來回答,要用自己的語言(非標(biāo)準(zhǔn)答案)表達(dá)出來。















 
 
 
















 
 
 
 