Android中的線程池 ThreadPoolExecutor

線程池的優(yōu)點(diǎn):

  1. 重用線程池中的線程,避免因?yàn)榫€程的創(chuàng)建和銷毀帶來的性能消耗
  2. 能有效的控制線程的最大并發(fā)數(shù),避免大量的線程之間因搶占系統(tǒng)資源而導(dǎo)致的阻塞現(xiàn)象
  3. 能夠?qū)€程進(jìn)行簡(jiǎn)單的管理,并提供定時(shí)執(zhí)行以及指定間隔循環(huán)執(zhí)行等功能

ThreadPoolExecutor:

Android中,用ThreadPoolExecutor來實(shí)現(xiàn)線程池的配置。
ThreadPoolExecutor文檔中文版
ThreadPoolExecutor文檔英文版

QQ截圖20160711141312.png

ThreadPoolExecutor的構(gòu)造方法

ThreadPoolExecutor的構(gòu)造方法有四個(gè),其實(shí)現(xiàn)如下:
```
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}

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

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
                          TimeUnit unit, BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
            Executors.defaultThreadFactory(), handler);
}

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
                          TimeUnit unit,BlockingQueue<Runnable> workQueue, 
                          ThreadFactory threadFactory, RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}
```
構(gòu)造方法的參數(shù)
  • corePoolSize
    程池中的核心線程數(shù),也就是是線程池中的最小線程數(shù);
    核心線程在allowCoreThreadTimeout被設(shè)置為true時(shí)會(huì)超時(shí)退出,默認(rèn)情況下不會(huì)退出;

  • maximumPoolSize
    最大線程池大小,當(dāng)活動(dòng)線程數(shù)達(dá)到這個(gè)值,后續(xù)任務(wù)會(huì)被阻塞

  • keepAliveTime
    線程池中超過corePoolSize數(shù)目的非核心線程最大存活時(shí)間;閑置時(shí)的超時(shí)時(shí)長(zhǎng),超過這個(gè)值后,閑置線程就會(huì)被回收

  • unit
    keepAliveTime 參數(shù)的時(shí)間單位。這是一個(gè)枚舉,詳情請(qǐng)參考TimeUnit

  • workQueue
    執(zhí)行前用于保持任務(wù)的隊(duì)列,也就是線程池的緩存隊(duì)列。此隊(duì)列僅保持由 execute 方法提交的 Runnable 任務(wù)
    關(guān)于三種提交策略這篇文章不錯(cuò)

  • threadFactory
    線程工廠,為線程池提供創(chuàng)建新線程的功能,它是一個(gè)接口,只有一個(gè)方法:Thread newThread(Runnable r)

  • RejectedExecutionHandler
    線程池對(duì)拒絕任務(wù)的處理策略。一般是隊(duì)列已滿或者無法成功執(zhí)行任務(wù),這時(shí)ThreadPoolExecutor會(huì)調(diào)用handler的rejectedExecution方法來通知調(diào)用者
    ThreadPoolExecutor默認(rèn)有四個(gè)拒絕策略:

      1、ThreadPoolExecutor.AbortPolicy()   直接拋出異常RejectedExecutionException
      2、ThreadPoolExecutor.CallerRunsPolicy()    直接調(diào)用run方法并且阻塞執(zhí)行
      3、ThreadPoolExecutor.DiscardPolicy()   直接丟棄后來的任務(wù)
      4、ThreadPoolExecutor.DiscardOldestPolicy()  丟棄在隊(duì)列中隊(duì)首的任務(wù)
    

也可以自己繼承RejectedExecutionHandler來寫拒絕策略.

ThreadPoolExecutor的執(zhí)行過程:

一個(gè)任務(wù)通過 execute(Runnable)方法被添加到線程池,任務(wù)就是一個(gè) Runnable類型的對(duì)象,任務(wù)的執(zhí)行方法就是Runnable類型對(duì)象的run()方法。

  1. 當(dāng)線程池小于corePoolSize時(shí),新提交任務(wù)將創(chuàng)建一個(gè)新線程執(zhí)行任務(wù),即使此時(shí)線程池中存在空閑線程
  2. 當(dāng)線程池達(dá)到corePoolSize時(shí),新提交任務(wù)將被放入workQueue中,等待線程池中任務(wù)調(diào)度執(zhí)行
  3. 當(dāng)提交任務(wù)數(shù)超過【maximumPoolSize+阻塞隊(duì)列大小】時(shí),新提交任務(wù)由RejectedExecutionHandler處理 (關(guān)于這里,網(wǎng)上90%以上的人說當(dāng)任務(wù)數(shù)>=maximumPoolSize時(shí)就會(huì)被拒絕,我不知道依據(jù)在哪里,也不知道代碼驗(yàn)證過沒,經(jīng)過我的驗(yàn)證這種說法是不成立的,具體的看下邊日志分析)
  4. 當(dāng)線程池中超過corePoolSize線程,空閑時(shí)間達(dá)到keepAliveTime時(shí),關(guān)閉空閑線程
  5. 當(dāng)設(shè)置allowCoreThreadTimeOut(true)時(shí),線程池中corePoolSize線程空閑時(shí)間達(dá)到keepAliveTime也將關(guān)閉
定制自己的線程池:
public class ThreadTestActivity extends AppCompatActivity {
    private final int CORE_POOL_SIZE = 1;//核心線程數(shù)
    private final int MAX_POOL_SIZE = 3;//最大線程數(shù)
    private final int BLOCK_SIZE = 2;//阻塞隊(duì)列大小
    private final long KEEP_ALIVE_TIME = 2;//空閑線程超時(shí)時(shí)間
    private ThreadPoolExecutor executorPool;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread_test);
        //創(chuàng)建線程池
        // 創(chuàng)建一個(gè)核心線程數(shù)為3、最大線程數(shù)為8,緩存隊(duì)列大小為5的線程池
        executorPool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME,
                TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(BLOCK_SIZE),
                Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        executorPool.allowCoreThreadTimeOut(true);
    }

    public void begin(View view) {
        for (int num = 0; num < 6; num++) {//每個(gè)500ms添加一個(gè)任務(wù)到隊(duì)列中
            try {
                Li("execute");// 監(jiān)聽相關(guān)數(shù)據(jù)
                executorPool.execute(new WorkerThread("thread-" + num));
            } catch (Exception e) {
                Log.e("threadtest", "AbortPolicy...");
            }
        }

        // 20s后,所有任務(wù)已經(jīng)執(zhí)行完畢,我們?cè)诒O(jiān)聽一下相關(guān)數(shù)據(jù)
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(20 * 1000);
                } catch (Exception e) {

                }
                Li("monitor after");
            }
        }).start();
    }

    private void Li(String mess) {
        Log.i("threadtest", "monitor " + mess
                        + " CorePoolSize:" + executorPool.getCorePoolSize()
                        + " PoolSize:" + executorPool.getPoolSize()
                        + " MaximumPoolSize:" + executorPool.getMaximumPoolSize()
                        + " ActiveCount:" + executorPool.getActiveCount()
                        + " TaskCount:" + executorPool.getTaskCount()

        );
    }

}

// 模擬耗時(shí)任務(wù)
public class WorkerThread implements Runnable {
    private String threadName;
    public WorkerThread(String threadName) {
        this.threadName = threadName;
    }
    @Override
    public synchronized void run() {

        int i = 0;
        boolean flag = true;
        try {
            while (flag) {
                Thread.sleep(1000);
                i++;
                Log.e("threadtest", "WorkerThread " + threadName + "  " + i);
                if (i >2) flag = false;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public String getThreadName() {
        return threadName;
    }
}

日志信息:


QQ截圖20160712161004.png

下面就來對(duì)日志信息進(jìn)行分析:

  1. 上邊粉色部分(1~6行),可以看到poolsize逐漸累加,一直加到最大線程數(shù)后不再增加,這呼應(yīng)了上述“執(zhí)行過程1”
  2. 接下來綠色部分()7行,驗(yàn)證了上邊我們說的“執(zhí)行過程3”,緩存隊(duì)列數(shù)為2,最大線程數(shù)為3,共有6條任務(wù),所以會(huì)有【 6-(2+3)】條任務(wù)被拒絕,這里拒絕策略我們用的是ThreadPoolExecutor.AbortPolicy()也就是直接拋出異常,也就是我們?nèi)罩镜牡?行
  3. 然后8~22行是任務(wù)的執(zhí)行過程,
  4. 其中藍(lán)色部分(8~16)行,我們可以看到有3條任務(wù)在同時(shí)執(zhí)行,也就是最大線程數(shù)
  5. 接下來的綠色(17~22行),在三條任務(wù)執(zhí)行完成后,剩余的排隊(duì)任務(wù)才開始執(zhí)行
  6. 最后,23行,20s后,線程都處于空閑狀態(tài),所以非核心線程會(huì)被回收,但是因?yàn)榇a中我們?cè)O(shè)置了executorPool.allowCoreThreadTimeOut(true),所以這時(shí)處于空閑狀態(tài)的核心線程也會(huì)被回收,這時(shí)池中的線程數(shù)為0
關(guān)于線程池的一些建議
  • 最大線程數(shù)一般設(shè)為2N+1最好,N是CPU核數(shù)

官方定義的四種線程池

其實(shí),本應(yīng)該先說官方定義的這四種線程池,然后再說自定義線程池,但是考慮到里邊的一些配置參數(shù),所以本帖先利用自定義線程池把各個(gè)配置參數(shù)理一下,然后再講官方定義的四種線程池,這樣也便于理解官方定義的這四種線程池
這四種線程池都是通過Executors的工廠方法來實(shí)現(xiàn)

1、FixedThreadPool

他是一種數(shù)量固定的線程池,且任務(wù)隊(duì)列也沒有大小限制;
它只有核心線程,且這里的核心線程也沒有超時(shí)限制,所以即使線程處于空閑狀態(tài)也不會(huì)被回收,除非線程池關(guān)閉;
當(dāng)所有的任務(wù)處于活動(dòng)狀態(tài),新任務(wù)都處于等待狀態(tài),知道所有線程空閑出來;
因?yàn)樗粫?huì)被回收,所以它能更快的響應(yīng);
源碼:

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

實(shí)現(xiàn):

    ExecutorService service = Executors.newFixedThreadPool(3);
    service.execute(new WorkerThread("thread-" + num));
2、CachedThreadPool

無界線程池,可以進(jìn)行自動(dòng)線程回收
他是一種線程數(shù)量不固定的線程池;
它只有非核心線程,且最大線程數(shù)為Integer.MAX_VALUE,也就是說線程數(shù)可以任意大;
當(dāng)池中的線程都處于活動(dòng)狀態(tài)時(shí),會(huì)創(chuàng)建新的線程來處理任務(wù),否則會(huì)利用空閑線程來處理任務(wù);所以,任何添加進(jìn)來的任務(wù)都會(huì)被立即執(zhí)行;
池中的空閑線程都有超時(shí)限制,為60s,超過這個(gè)限制就會(huì)被回收,當(dāng)池中的所有線程都處于閑置狀態(tài)時(shí),都會(huì)因超時(shí)而被回收,這個(gè)時(shí)候,她幾乎不占用任何系統(tǒng)資源;
適合做大量的耗時(shí)較少的任務(wù);
源碼:

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

實(shí)現(xiàn):

    ExecutorService service = Executors.newCachedThreadPool();
    service.execute(new WorkerThread("thread-"));
3、SingleThreadExecutor

只有一個(gè)核心線程,所有任務(wù)都在同一線程中按序執(zhí)行,這樣也就不需要處理線程同步的問題;
源碼:

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

實(shí)現(xiàn):

    ExecutorService service = Executors.newSingleThreadExecutor();
    service.execute(new WorkerThread("thread-"));
4、ScheduledThreadPool

它的核心線程數(shù)量是固定的,而非核心線程是沒有限制的,且非核心線程空閑時(shí)會(huì)被回收;
適合執(zhí)行定時(shí)任務(wù)和具有固定周期的任務(wù)
源碼:

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE,
              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
              new DelayedWorkQueue());
    }

實(shí)現(xiàn):

    ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
    或
    ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();

    threadPool.schedule(runnable, 20, TimeUnit.SECONDS);// 20秒后執(zhí)行任務(wù)
    或
    threadPool.scheduleAtFixedRate(runnable,10,20,TimeUnit.SECONDS);//延遲10s,每20s執(zhí)行一次任務(wù)

由于本人技術(shù)有限,避免不了出現(xiàn)一些錯(cuò)誤或者理解有偏差描述不清楚的地方,請(qǐng)大家諒解并提醒我:)

上一篇:AsyncTask
再來一篇:java中的thread

更多內(nèi)容請(qǐng)關(guān)注我的Android專題
本文出自:http://www.lxweimin.com/users/c1b4a5542220/latest_articles
轉(zhuǎn)載請(qǐng)注明出處!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容