1. 程式人生 > >執行緒精進指南之執行緒池進階

執行緒精進指南之執行緒池進階

為什麼引進執行緒池

魚池,我們可以釣出來一條再放回去,釣出來一條再放回去,這樣來撩魚。

那執行緒池該如何玩呢?對,取出來一“條”執行緒,用完後再扔回去,再取出來,再扔....

執行緒池的優點:

避免大量的建立和銷燬帶來的效能開銷

避免大量的執行緒間因互相搶佔系統資源導致的阻塞現象。

能夠對執行緒進行簡單的管理並提供定時執行、間隔執行等功能。

缺點

佔用一定的記憶體空間。

執行緒越多CPU的排程開銷越大。

程式的複雜度會上升。

執行緒池的基本使用

使用執行緒池 ,肯定要對“池”進行配置,像基本的池多大啊,能容納多少魚啊,等這些是需要建造前就要確定的,因此我們搞池之前先設計

• int corePoolSize

 核心執行緒最大數

 無論是閒置還是工作中,永遠都不會銷燬的執行緒,會一直線上程池中存在,那我們是不是永遠都奈何不了它呢,當然不會,把ThreadPoolExecutorallowCoreThreadTimeOut這個屬性設定為true,超過規定時長也會銷燬

• int maximumPoolSize 執行緒總數最大值

 就是我們所有的執行緒啊,對,包括非核心的和上邊講的核心的

• long keepAliveTime

 如果不是核心執行緒,超過這個引數的時間就會被幹掉

• TimeUnit unit

 時間總是有單位的吧,對就是上邊KeepAliveTime的時間引數哇

 型別時列舉,這裡舉幾種常用的,反正說多了也記不住,需要時候

IDEA會提示

 SECONDS : 秒

 MINUTES : 分

 HOURS : 小時

 DAYS : 天

• BlockingQueue workQueue  

 佇列內容較多,我們下邊單獨講

• ThreadFactory threadFactory

 這個一般不用,沒必要管啦

• RejectedExecutionHandler handler

 如果執行的過程中,拋異常了,我們可以用這個來指定,但是系統有預設的,因此這個也可以不用

使用執行緒池當然離不開Executor這個介面,具體的實現類在ThreadPoolExecutor中,so我們簡單瞭解下這個類

//對,使用的就是這幾個構造,引數我們上邊已經將過了


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

常用的幾種執行緒池

執行緒都池都是是使用Executors這個類創建出來的

• CachedThreadPool()

 可快取執行緒池:

 執行緒數無限制

 優先使用空閒執行緒,如果沒有才新建執行緒

//建立方式
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

//原始碼中的定義
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

• FixedThreadPool()

 固定長度的執行緒池

 可以控制執行緒的數量

 如果超過則必須排隊執行

//建立方式
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(執行緒數量);

//原始碼中的定義
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

• ScheduledThreadPool()

 對,就是它可以定時

//建立方法
ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(最大執行緒數);


//原始碼中的定義
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}

• SingleThreadExecutor()

 所有任務排隊執行,一次只能執行一個任務

//建立方法
ExecutorService singleThreadPool = Executors.newSingleThreadPool();

//原始碼中的定義
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));

佇列

佇列類似我們的集合,實現了Collection介面

佇列中排隊執行的是我們runnable物件

常用的佇列有如下幾種

• SynchronousQueue:

 有任務來就執行交給空閒執行緒,如果沒有就新建執行緒執行,so 執行緒數設定儘可能大即Integer.MAX_VALUE

• LinkedBlockingQueue:

 永遠在核心執行緒內使用執行緒,如果超過了核心的執行緒就在佇列中等待執行

• ArrayBlockingQueue:

 優先使用核心執行緒數,其次使用非核心的,如果用完了就進入佇列等待

• DelayQueue:

 想進入佇列必須實現Delayed介面,達到指定時間後,方可執行任務

讀書百遍不如程式碼十遍,提升的唯一道路唯有你的手速!