【揭秘】RejectedExecutionHandler和ThreadFactory

2024年2月6日 19点热度 0人点赞

線程池高手進階:揭秘ThreadPoolExecutor的小妙招! - 程序員古德

RejectedExecutionHandler總結

ThreadPoolExecutor 是 Java 中用於創建和管理線程池的接口,當線程池中的任務隊列已滿,並且線程池中的線程數量已經達到最大時,如果再有新的任務提交,就需要一個策略來處理這些無法執行的任務。它 提供了四種拒絕策略,都是 RejectedExecutionHandler 接口的實現,如下:

  1. AbortPolicy(默認策略):直接拋出一個 RejectedExecutionException 異常。
  2. CallerRunsPolicy:調用執行任務的 execute 方法的線程來運行任務,如果執行程序已經關閉,那麼任務將被拋棄。
  3. DiscardPolicy:無法執行的任務將被拋棄,不會拋出任何異常。
  4. DiscardOldestPolicy:如果執行程序尚未關閉,則位於工作隊列頭部的任務將被刪除,然後重試執行任務(如果再次失敗,則重復此過程)。

以下是使用ThreadPoolExecutor的代碼示例,如下:

import java.util.concurrent.*;  
public class ThreadPoolExecutorDemo {  
    public static void main(String[] args) {  
        // 創建一個固定大小的線程池  
        int corePoolSize = 2;  
        int maximumPoolSize = 4;  
        long keepAliveTime = 10L;  
        TimeUnit unit = TimeUnit.SECONDS;  
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);  
        // 使用不同的拒絕策略  
        RejectedExecutionHandler abortPolicy = new ThreadPoolExecutor.AbortPolicy();  
        RejectedExecutionHandler callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();  
        RejectedExecutionHandler discardPolicy = new ThreadPoolExecutor.DiscardPolicy();  
        RejectedExecutionHandler discardOldestPolicy = new ThreadPoolExecutor.DiscardOldestPolicy();  
        // 創建線程池並設置拒絕策略  
        ThreadPoolExecutor executor1 = new ThreadPoolExecutor(  
                corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, abortPolicy);  
        ThreadPoolExecutor executor2 = new ThreadPoolExecutor(  
                corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, callerRunsPolicy);  
        ThreadPoolExecutor executor3 = new ThreadPoolExecutor(  
                corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, discardPolicy);  
        ThreadPoolExecutor executor4 = new ThreadPoolExecutor(  
                corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, discardOldestPolicy);  
        // 提交任務  
        for (int i = 0; i < 10; i  ) {  
            final int taskId = i;  
            executor1.execute(() -> System.out.println("Executing task "   taskId   " with AbortPolicy"));  
            executor2.execute(() -> System.out.println("Executing task "   taskId   " with CallerRunsPolicy"));  
            executor3.execute(() -> System.out.println("Executing task "   taskId   " with DiscardPolicy"));  
            executor4.execute(() -> System.out.println("Executing task "   taskId   " with DiscardOldestPolicy"));  
        }  
    }  
}

在上面的代碼示例中,由於工作隊列和線程池的大小都設置得很小,所以提交的任務會很快填滿隊列和線程池,從而觸發拒絕策略,不同的拒絕策略適用於不同的場景,在實際應用中,應該根據具體需求來合理設置線程池的大小、工作隊列的容量以及拒絕策略。

ThreadFactory總結

ThreadFactory接口常用於在ThreadPoolExecutor中管理控制線程的名稱、優先級、是否守護線程以及其他線程屬性。下面是一個簡單的ThreadFactory使用案例,案例中定義了一個CustomThreadFactory類,如下代碼:

import java.util.concurrent.ThreadFactory;  
import java.util.concurrent.atomic.AtomicInteger;  
public class CustomThreadFactory implements ThreadFactory {  
    private final String prefix;  
    private final AtomicInteger threadNumber = new AtomicInteger(1);  
    public CustomThreadFactory(String prefix) {  
        this.prefix = prefix;  
    }  
    @Override  
    public Thread newThread(Runnable r) {  
        // 創建一個新線程  
        Thread thread = new Thread(r);  
        // 設置線程名稱,使用前綴和遞增的數字  
        thread.setName(prefix   "-"   threadNumber.getAndIncrement());  
        // 可以設置其他屬性,比如優先級、守護狀態等  
        // thread.setPriority(Thread.MAX_PRIORITY);  
        // thread.setDaemon(false);  
        return thread;  
    }  
}

在上面代碼中:

  1. CustomThreadFactory類實現了ThreadFactory接口,並重寫了newThread方法。
  2. 構造函數接受一個prefix參數,用於生成線程名稱的前綴。
  3. 使用AtomicInteger來生成唯一的線程編號,確保在多線程環境下編號不會重復。
  4. 在newThread方法中,創建一個新的Thread對象,並通過setName方法設置線程的名稱,這裡使用前綴和遞增的編號來構建線程名稱,方便在日志或調試時識別線程。
  5. 還可以根據需要調用其他Thread方法來設置線程的優先級、守護狀態等屬性。

如下是CustomThreadFactory的使用方法,如下:

import java.util.concurrent.ThreadPoolExecutor;  
import java.util.concurrent.TimeUnit;  
import java.util.concurrent.SynchronousQueue;  
public class ThreadPoolExample {  
    public static void main(String[] args) {  
        // 創建一個具有自定義線程工廠的線程池  
        ThreadPoolExecutor executor = new ThreadPoolExecutor(  
            5, // corePoolSize  
            10, // maximumPoolSize  
            60L, // keepAliveTime  
            TimeUnit.SECONDS, // unit for keepAliveTime  
            new SynchronousQueue<>(), // workQueue  
            new CustomThreadFactory("CustomThreadPool-") // 自定義線程工廠  
        );  
        // 提交任務給線程池  
        for (int i = 0; i < 20; i  ) {  
            final int taskId = i;  
            executor.submit(() -> {  
                // 執行任務  
                System.out.println("Task "   taskId   " is running on thread "   Thread.currentThread().getName());  
            });  
        }  
        // 關閉線程池(這通常是在應用程序關閉時完成的)  
        // executor.shutdown();  
    }  
}

關註我,每天學習互聯網編程技術 - 程序員古德

END!