1. 程式人生 > >一、Executors建立執行緒池

一、Executors建立執行緒池

總結

Java中建立執行緒池很簡單,只需要呼叫Executors中相應的靜態方法即可,比如Executors.newFixedThreadPool(int nThreads),但是便捷不僅隱藏了複雜性,也為我們埋下了潛在的隱患(OOM,執行緒耗盡)。

Executors建立執行緒池便捷方法列表:

方法名 功能
newFixedThreadPool(int nThreads) 建立固定大小的執行緒池
newSingleThreadExecutor() 建立只有一個執行緒的執行緒池
newCachedThreadPool() 建立一個不限執行緒數上限的執行緒池,任何提交的任務都將立即執行
使用注意事項:
1、小程式使用這些快捷方法沒什麼問題

2、對於服務端需要長期執行的程式,建立執行緒池應該直接使用ThreadPoolExecutor的構造方法。上述Executors底層實現也是ThreadPoolExecutor

-------------------------------------- 分 割 線 -----------------------------------------------------
1.FixedThreadPool 定長執行緒池

原始碼:

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

根據原始碼可以看出:

  1. 該執行緒池的最大執行緒數等於核心執行緒數,所以在預設情況下,該執行緒池的執行緒不會因為閒置狀態超時而被銷燬。
  2. 如果當前執行緒數小於核心執行緒數,並且也有閒置執行緒的時候提交了任務,這時也不會去複用之前的閒置執行緒,會建立新的執行緒去執行任務。如果當前執行任務數大於了核心執行緒數,大於的部分就會進入佇列等待。等著有閒置的執行緒來執行這個任務。

建立方法:

//nThreads => 最大執行緒數即maximumPoolSize
ExecutorService mFixedThreadPool= Executors.newFixedThreadPool(int nThreads);

//threadFactory => 建立執行緒的方法,用得少 ExecutorService mFixedThreadPool= Executors.newFixedThreadPool(int nThreads, ThreadFactory threadFactory);

用法:

private void startDownload(final ProgressBar progressBar, final int i) {
        mFixedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
               //....邏輯程式碼自己控制
            }
        });
    }
2.SingleThreadPool

原始碼:

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

根據原始碼可以看出:

  1. 有且僅有一個工作執行緒執行任務
  2. 所有任務按照指定順序執行,即遵循佇列的入隊出隊規則

建立方法: ExecutorService mSingleThreadPool = Executors.newSingleThreadPool();

用法同上。

3.可快取執行緒池CachedThreadPool()

原始碼:

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

根據原始碼可以看出:

  1. 這種執行緒池內部沒有核心執行緒,執行緒的數量是有沒限制的。
  2. 在建立任務時,若有空閒的執行緒時則複用空閒的執行緒,若沒有則新建執行緒。
  3. 沒有工作的執行緒(閒置狀態)在超過了60S還不做事,就會銷燬。

建立方法:

ExecutorService mCachedThreadPool = Executors.newCachedThreadPool();

用法:

//開始下載
private void startDownload(final ProgressBar progressBar, final int i) {
        mCachedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                int p = 0;
                progressBar.setMax(10);//每個下載任務10秒
                while (p < 10) {
                    p++;
                    progressBar.setProgress(p);
                    Bundle bundle = new Bundle();
                    Message message = new Message();
                    bundle.putInt("p", p);
                    //把當前執行緒的名字用handler讓textview顯示出來
                    bundle.putString("ThreadName", Thread.currentThread().getName());
                    message.what = i;
                    message.setData(bundle);
                    mHandler.sendMessage(message);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
4.ScheduledThreadPool

原始碼:

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

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

根據原始碼可以看出: DEFAULT_KEEPALIVE_MILLIS就是預設10L,這裡就是10秒。這個執行緒池有點像是吧CachedThreadPool和FixedThreadPool 結合了一下。

  1. 不僅設定了核心執行緒數,最大執行緒數也是Integer.MAX_VALUE。
  2. 這個執行緒池是上述4箇中為唯一個有延遲執行和週期執行任務的執行緒池。

建立:

//nThreads => 最大執行緒數即maximumPoolSize
ExecutorService mScheduledThreadPool = Executors.newScheduledThreadPool(int corePoolSize);

一般的執行任務方法和上面的都大同小異,我們主要看看延時執行任務和週期執行任務的方法。

//表示在3秒之後開始執行我們的任務。
mScheduledThreadPool.schedule(new Runnable() {
            @Override
            public void run() {
            //....
            }
        }, 3, TimeUnit.SECONDS);
//延遲3秒後執行任務,從開始執行任務這個時候開始計時,每7秒執行一次不管執行任務需要多長的時間。 
mScheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
             //....
            }
        },3, 7, TimeUnit.SECONDS);
/**延遲3秒後執行任務,從任務完成時這個時候開始計時,7秒後再執行,
*再等完成後計時7秒再執行也就是說這裡的迴圈執行任務的時間點是
*從上一個任務完成的時候。
*/
mScheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
             //....
            }
        },3, 7, TimeUnit.SECONDS);

以上就是常用的四個執行緒池以及他們的實現原理。