說一說如何優雅的關閉線程池?

優雅地關閉線程池意味着確保所有正在執行的任務都能完成,同時不會接受新的任務,並且不會突然終止正在運行的線程。

Java 提供了幾種方法來優雅地關閉線程池,主要通過 shutdown() 和 awaitTermination() 方法來實現。

示例和講解

import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

public class GracefulShutdownExample {

    public static void main(String[] args) {
        // 創建一個固定大小的線程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        // 提交一些任務給線程池
        for (int i = 0; i < 5; i++) {
            executorService.submit(new Task(i));
        }

        // 發起關閉線程池的請求,不再接受新任務
        executorService.shutdown();

        try {
            // 等待線程池中的所有任務完成,或者超時
            if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
                // 如果在指定時間內沒有完成,強制關閉線程池
                executorService.shutdownNow();
                System.out.println("線程池強制關閉");
            } else {
                System.out.println("線程池優雅關閉");
            }
        } catch (InterruptedException e) {
            // 捕獲InterruptedException異常,強制關閉線程池
            executorService.shutdownNow();
            Thread.currentThread().interrupt(); // 恢復被中斷的狀態
            System.out.println("線程池在中斷時被關閉");
        }
    }

    static class Task implements Runnable {
        private final int taskId;

        public Task(int taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            System.out.println("任務 " + taskId + " 開始執行");
            try {
                // 模擬任務執行時間
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // 恢復被中斷的狀態
                System.out.println("任務 " + taskId + " 被中斷");
            }
            System.out.println("任務 " + taskId + " 完成");
        }
    }
}

講解

  1. 1. 創建線程池

    ExecutorService executorService = Executors.newFixedThreadPool(2);

    這裏創建了一個固定大小爲 2 的線程池。

  2. 2. 提交任務

    for (int i = 0; i < 5; i++) {
        executorService.submit(new Task(i));
    }

    提交了 5 個任務到線程池中。

  3. 3. 關閉線程池

    executorService.shutdown();

    調用 shutdown() 方法,線程池進入關閉狀態,不再接受新任務,但會繼續執行已經提交的任務。

  4. 4. 等待任務完成

    if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) {
        executorService.shutdownNow();
        System.out.println("線程池強制關閉");
    } else {
        System.out.println("線程池優雅關閉");
    }

    調用 awaitTermination(long timeout, TimeUnit unit) 方法,等待線程池中的任務在指定的時間內完成。如果在規定時間內沒有完成,調用 shutdownNow() 強制關閉線程池。

  5. 5. 處理中斷異常

    } catch (InterruptedException e) {
        executorService.shutdownNow();
        Thread.currentThread().interrupt();
        System.out.println("線程池在中斷時被關閉");
    }

    捕獲 InterruptedException 異常,強制關閉線程池,並恢復被中斷的狀態。

  6. 6. 任務類

    static class Task implements Runnable {
        // ... 模擬任務執行,可能會拋出 InterruptedException
    }

    定義了一個簡單的任務類,每個任務會睡眠 2 秒鐘,模擬執行時間。

關鍵點

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/c6PlbmTNJY3JO0BWvx0mow