Java - Thread 執行緒(四) Thread Pool

By sunwc 2023-03-24 Java

Thread Pool 特性

  • 背景:經常創建和銷毀、使用量特別大的資源,例如併發情況下的執行緒,對效能影響很大
  • 思路:提前創建 Multi thread,放入 Thread Pool中,使用時直接取得,使用完後放回池中。可以避免頻繁創建與銷毀、實現重複利用。類似生活中大眾交通工具
  • 好處:
    • 提高響應速度(減少了創建新 Thread 的時間)
    • 降低資源消耗(重複利用Thread Pool中的Thread,不需要每次都創建)
    • 便於 Thread 管理
      • corePoolSize: 核心池的大小
      • maximumPoolSize: 最大 Thread 數
      • keepAliveTime: Thread 在沒有任務時最多保持多長時間後會終止

Thread Pool 相關 API

  • JDK 5.0 起提供了 Thread Pool 相關 API: ExecutorServiceExecutors
  • interface ExecutorService:它的常見子類別 ThreadPoolExecutor
    • void execute(Runnable command):執行任務/ 命令,沒有回傳值,一般用來執行 Runnable
    • Future submit(Callable task):執行任務,有回傳值,一般用來執行 Callable
    • void shutdown():關閉 Thread Pool
  • interface Executor:工具類、Thread Pool 的工廠類,用於創建並回傳不同類型的 Thread Pool
    • Executors.newCachedThreadPool():創建一個可根據需要創建新 Thread的 Thread Pool
    • Executors.newFixedThreadPool(n):創建一個可重用固定 Thread 數的 Thread Pool
    • Executors.newSingleThreadPool():創建一個只有一個 Thread 的 Thread Pool
    • Executors.newScheduledThreadPool(n):創建一個 Thread Pool,它可以安排在給定延遲後 執行命令 或者 定期地執行

使用 Thread Pool 實現 Multi-threading 步驟

1.提供指定 Thread 數的 Thread Pool

2.執行指定的 Thread,需要提供Runnable 或 Callable 的實現類別物件

3.關閉 Thread Pool

例子

/**
 * @author sunwc
 * @create 2023-03-25 上午 10:22
 */
public class ThreadPool {

    public static void main(String[] args) {

        ExecutorService executorService = Executors.newFixedThreadPool(10);

        // 設置Thread Pool 屬性
        // 1. 透過 interface ExecutorService.getClass() 取得它的實現類別
        System.out.println(executorService.getClass());// java.util.concurrent.ThreadPoolExecutor
        // 2. 取得實現類ThreadPoolExecutor後,就可以更改Thread Pool 屬性了
        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
        threadPoolExecutor.setCorePoolSize(15);

        // 適合使用於Runnable
        executorService.execute(new EvenNumThread());

        // 適合使用於Callable
        executorService.submit(new OddNumThread());

        // 關閉 Thread Pool
        executorService.shutdown();

    }
}

/**
 * 輸出1-25間的偶數
 */
class EvenNumThread implements Runnable {

    @Override
    public void run() {
        Thread.currentThread().setName("偶數執行緒");

        for (int i = 1; i <= 25; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

/**
 * 輸出1-25間的奇數
 */
class OddNumThread implements Callable {

    @Override
    public Object call() throws Exception {
        Thread.currentThread().setName("奇數執行緒");

        for (int i = 1; i <= 25; i++) {
            if (i % 2 != 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
        return null;
    }
}

輸出結果:

class java.util.concurrent.ThreadPoolExecutor
偶數執行緒:2
偶數執行緒:4
偶數執行緒:6
偶數執行緒:8
偶數執行緒:10
偶數執行緒:12
偶數執行緒:14
偶數執行緒:16
偶數執行緒:18
偶數執行緒:20
偶數執行緒:22
偶數執行緒:24
奇數執行緒:1
奇數執行緒:3
奇數執行緒:5
奇數執行緒:7
奇數執行緒:9
奇數執行緒:11
奇數執行緒:13
奇數執行緒:15
奇數執行緒:17
奇數執行緒:19
奇數執行緒:21
奇數執行緒:23
奇數執行緒:25

總結

如何創建 Thread 相關的概念,不知不覺寫了好幾篇文章,雖然實際開發中,通常不會自己建,只要使用框架幫我們寫好的就可以了;但是有了 Thread 底層的基礎觀念,使用起來也比較確定用法是正確的 :)

在把這個系列的文章集合起來:

有關創建多執行緒 (Multi-threading) 的方式 - 繼承 Thread 類,可以參考我的另一篇文章 Java - Thread 執行緒(一)

有關創建多執行緒的方式 - 實現 interface Runnable,可以參考我的另一篇文章 Java - Thread 執行緒(二) - interface Runnable

有關創建多執行緒的方式 - 實現 interface Runnable,可以參考我的另一篇文章 Java - Thread 執行緒(三) - interface Callable