1. 程式人生 > >Java線程池ThreadPoolExecutor&&Executors

Java線程池ThreadPoolExecutor&&Executors

同步 amp keep inter 拒絕 順序 fifo 重點 edt

一、先看看傳統的開啟線程

new Thread(new Runnable() {
    @Override
    public void run() {
    }
}).start();

缺點:

1、每次new Thread新建對象性能差。

2、線程缺乏統一管理,可能無限制新建線程,相互之間競爭,及可能占用過多系統資源導致死機或oom。

3、缺乏更多功能,如定時執行、定期執行、線程中斷。

二、在看看ThreadPoolExecutor

構造函數:

public ThreadPoolExecutor(int corePoolSize,
        
int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {}

參數說明:

corePoolSize:線程池核心線程數(平時保留的線程數)
maximumPoolSize:線程池最大線程數(當workQueue都放不下時,啟動新線程,最大線程數)

keepAliveTime:超出corePoolSize數量的線程的保留時間。
unit:keepAliveTime單位
workQueue:阻塞隊列,存放來不及執行的線程
  ArrayBlockingQueue:構造函數一定要傳大小
  LinkedBlockingQueue:構造函數不傳大小會默認為(Integer.MAX_VALUE ),當大量請求任務時,容易造成 內存耗盡。
  SynchronousQueue:同步隊列,一個沒有存儲空間的阻塞隊列 ,將任務同步交付給工作線程。
  PriorityBlockingQueue : 優先隊列
threadFactory:線程工廠
handler:飽和策略
AbortPolicy(默認):直接拋棄
  CallerRunsPolicy:用調用者的線程執行任務
  DiscardOldestPolicy:拋棄隊列中最久的任務
  DiscardPolicy:拋棄當前任務

劃重點:

1、當線程池小於corePoolSize時,新提交任務將創建一個新線程執行任務,即使此時線程池中存在空閑線程。
2、當線程池達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行
3、當workQueue已滿,且maximumPoolSize>corePoolSize時,新提交任務會創建新線程執行任務
4、當提交任務數超過maximumPoolSize時,新提交任務由RejectedExecutionHandler處理
5、當線程池中超過corePoolSize線程,空閑時間達到keepAliveTime時,關閉空閑線程
6、當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閑時間達到keepAliveTime也將關閉

三、Executors可創建預定義的線程池

1、FixedThreadPool:創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

特點:

1)、corePoolSize與maximumPoolSize相等,即其線程全為核心線程,是一個固定大小的線程池,是其優勢;
2)、keepAliveTime = 0 該參數默認對核心線程無效,而FixedThreadPool全部為核心線程;
3)、workQueue 為LinkedBlockingQueue(無界阻塞隊列),隊列最大值為Integer.MAX_VALUE。如果任務提交速度持續大余任務處理速度,會造成隊列大量阻塞。因為隊列很大,很有可能在拒絕策略前,內存溢出。是其劣勢;
4)、FixedThreadPool的任務執行是無序的;

適用場景:可用於Web服務瞬時削峰,但需註意長時間持續高峰情況造成的隊列阻塞。

2、CachedThreadPool:創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

特點:

1)、corePoolSize = 0,maximumPoolSize = Integer.MAX_VALUE,即線程數量幾乎無限制;
2)、keepAliveTime = 60s,線程空閑60s後自動結束。
3)、workQueue 為 SynchronousQueue 同步隊列,這個隊列類似於一個接力棒,入隊出隊必須同時傳遞,因為CachedThreadPool線程創建無限制,不會有隊列等待,所以使用SynchronousQueue;

適用場景:快速處理大量耗時較短的任務,如Netty的NIO接受請求時,可使用CachedThreadPool。

3、SingleThreadExecutor:創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

4、ScheduledThreadPool:創建一個定長線程池,支持定時及周期性任務執行。

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

代碼樣例:

public class Test {
    private ExecutorService cachePool = Executors.newCachedThreadPool();

    private void test() {
        for (int i = 0; i < 10; i++) {
            cachePool.execute(new Job());
        }
        cachePool.shutdown();
    }

    class Job implements Runnable {
        @Override
        public void run() {
            System.out.println("執行任務");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
            }
        }
    }

    public static void main(String[] args) {
        new ExecutorServiceTest().test();
    }
}

參考:

https://www.jianshu.com/p/f030aa5d7a28

https://segmentfault.com/a/1190000015368896?utm_source=tag-newest

Java線程池ThreadPoolExecutor&&Executors