Android使用ThreadPool

    線程池(ThreadPool):一種線程使用模式。

    What?不(什)知(麼)所(東)謂(東)。那麼首先我們得了解什麼事線程,線程一般理解爲我們順序執行某一任務的最小執行單元,同一時間只做一件事情。而線程的創建和銷燬在系統裏面是有開銷的,而且還比較大。

    我們來想想我們使用線程的方式一般爲new Thread() 這樣做是有很多弊端的,1、創建線程是有開銷的 2、線程的生命週期不可控,容易引起內存泄漏  3、線程使用混亂,最後自己創建了多少線程不清楚,無法有效的維護。而線程池的目的就是幫我們有效的維護我們的線程,同時儘量減少線程的創建、銷燬的開銷。

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

 corePoolSize:核心線程池大小
maximumPoolSize:最大線程池大小
keepAliveTime:線程池最大空閒時間
unit:時間單位
workQueue:線程等待隊列
threadFactory:線程創建工廠
handler:拒絕策略


我們可以用ThreadPoolExecutor來創建線程池,也可以用Executors的靜態實現類創建我們的線程池。

1、Executors.newFixedThreadPool(N)
創建有N條核心線程沒有非核心線程的線程池,核心線程不會被回收。當超過N數量的線程需排隊等待前面線程執行完畢方可執行。

private void startTheadPool(){
        //通過Executors.newFixedThreadPool(N)創建的線程有N條固定數量線程的線程池,僅有核心線程且沒有超時策略,線程不會被回收。
        //該方法創建的線程池沒有非核心線程  當超過N數量的線程會等待前面線程執行完纔會執行
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        for (int i = 0; i < 10; i++){
            final int index = i;
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                     Log.e(TAG,"CFixedThreadPool Start Run: 任務 = "+index+",線程 = "+Thread.currentThread().getName());
                    try {
                        Thread.sleep(2000);
                    }catch (InterruptedException e){

                    }
                }
            };
            executorService.execute(runnable);
        }
    }

執行結果如下:

2019-08-13 15:26:44.674 21796-21850/com.calm.cthreadpool E/CFixedThreadPool: CFixedThreadPool Start Run: 任務 = 0,線程 = pool-1-thread-1
2019-08-13 15:26:44.675 21796-21851/com.calm.cthreadpool E/CFixedThreadPool: CFixedThreadPool Start Run: 任務 = 1,線程 = pool-1-thread-2
2019-08-13 15:26:46.676 21796-21850/com.calm.cthreadpool E/CFixedThreadPool: CFixedThreadPool Start Run: 任務 = 2,線程 = pool-1-thread-1
2019-08-13 15:26:46.676 21796-21851/com.calm.cthreadpool E/CFixedThreadPool: CFixedThreadPool Start Run: 任務 = 3,線程 = pool-1-thread-2
2019-08-13 15:26:48.677 21796-21850/com.calm.cthreadpool E/CFixedThreadPool: CFixedThreadPool Start Run: 任務 = 4,線程 = pool-1-thread-1
2019-08-13 15:26:48.677 21796-21851/com.calm.cthreadpool E/CFixedThreadPool: CFixedThreadPool Start Run: 任務 = 5,線程 = pool-1-thread-2
2019-08-13 15:26:50.679 21796-21851/com.calm.cthreadpool E/CFixedThreadPool: CFixedThreadPool Start Run: 任務 = 7,線程 = pool-1-thread-2
2019-08-13 15:26:50.679 21796-21850/com.calm.cthreadpool E/CFixedThreadPool: CFixedThreadPool Start Run: 任務 = 6,線程 = pool-1-thread-1
2019-08-13 15:26:52.680 21796-21851/com.calm.cthreadpool E/CFixedThreadPool: CFixedThreadPool Start Run: 任務 = 9,線程 = pool-1-thread-2
2019-08-13 15:26:52.680 21796-21850/com.calm.cthreadpool E/CFixedThreadPool: CFixedThreadPool Start Run: 任務 = 8,線程 = pool-1-thread-1

可以看到一次執行了2條線程,而2秒之後待前2條線程執行完畢才繼續執行下2條線程。而線程始終爲線程池裏的thread-1和thread-2。

2、Executors.newCachedThreadPool()

該方法創建的線程只有非核心線程,數量爲無限大。沒有核心線程。適合做一些量比較大但耗時較短的操作。

private void startTheadPool(){
        //CachedThreadPool是一種線程數量不定的線程池,只有非核心線程,線程數量爲無限大。
        //比較適合做一些大量的耗時較少的任務
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++){
            final int index = i;
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    Log.e(TAG,"CCachedThreadPool Start Run: 任務 = "+index+",線程 = "+Thread.currentThread().getName());
                    try {
                        Thread.sleep(2000);
                    }catch (InterruptedException e){

                    }
                }
            };
            executorService.execute(runnable);
        }
    }

執行結果如下:

2019-08-13 15:34:00.398 21796-22119/com.calm.cthreadpool E/CCachedThreadPool: CCachedThreadPool Start Run: 任務 = 0,線程 = pool-2-thread-1
2019-08-13 15:34:00.401 21796-22120/com.calm.cthreadpool E/CCachedThreadPool: CCachedThreadPool Start Run: 任務 = 1,線程 = pool-2-thread-2
2019-08-13 15:34:00.403 21796-22121/com.calm.cthreadpool E/CCachedThreadPool: CCachedThreadPool Start Run: 任務 = 2,線程 = pool-2-thread-3
2019-08-13 15:34:00.405 21796-22122/com.calm.cthreadpool E/CCachedThreadPool: CCachedThreadPool Start Run: 任務 = 3,線程 = pool-2-thread-4
2019-08-13 15:34:00.405 21796-22123/com.calm.cthreadpool E/CCachedThreadPool: CCachedThreadPool Start Run: 任務 = 4,線程 = pool-2-thread-5
2019-08-13 15:34:00.407 21796-22125/com.calm.cthreadpool E/CCachedThreadPool: CCachedThreadPool Start Run: 任務 = 6,線程 = pool-2-thread-7
2019-08-13 15:34:00.408 21796-22126/com.calm.cthreadpool E/CCachedThreadPool: CCachedThreadPool Start Run: 任務 = 7,線程 = pool-2-thread-8
2019-08-13 15:34:00.409 21796-22127/com.calm.cthreadpool E/CCachedThreadPool: CCachedThreadPool Start Run: 任務 = 8,線程 = pool-2-thread-9
2019-08-13 15:34:00.413 21796-22128/com.calm.cthreadpool E/CCachedThreadPool: CCachedThreadPool Start Run: 任務 = 9,線程 = pool-2-thread-10
2019-08-13 15:34:00.418 21796-22124/com.calm.cthreadpool E/CCachedThreadPool: CCachedThreadPool Start Run: 任務 = 5,線程 = pool-2-thread-6

我們可以看到基本在同一時刻執行了所有的線程,並且執行的線程均未重複。

3、Executors.newScheduledThreadPool(N)

該方法創建N條核心線程和不限制的非核心線程的線程池。一般來說,該線程池執行的爲帶有一定延遲或週期調度的線程任務。

private void startTheadPool(){
        //ScheduledExecutorService(N) 有N條核心線程且有非限制的非核心線程,非核心線程閒置時會被立即回收。
        //主要用於執行定時任務和具有固定週期的重複任務
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
        for (int i = 0; i < 10; i++){
            final int index = i;
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    Log.e(TAG,"CScheduleThreadPool Start Run: 任務 = "+index+",線程 = "+Thread.currentThread().getName());
                    try {
                        Thread.sleep(2000);
                    }catch (InterruptedException e){

                    }
                }
            };
            //延遲2秒執行runnable
            executorService.schedule(runnable,2000, TimeUnit.MILLISECONDS);
        }
    }

執行效果爲線程開始後延遲2秒之後纔開始真正的執行線程裏的內容。除了延遲,其效果與FixedThreadPool執行效果類似。

4、Executors.newSingleThreadExecutor()

創建一個只有唯一線程的線程池。所有任務均順序等待該唯一線程的執行。因爲只有唯一線程,所以我們也不用去考慮線程通過的問題。

private void startTheadPool(){
        //SingleTheadExecutor只有一個核心線程,無非核心線程  所有任務都在一個線程裏順序執行 不需要線程同步
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++){
            final int index = i;
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    Log.e(TAG,"CSingleThreadExecutor Start Run: 任務 = "+index+",線程 = "+Thread.currentThread().getName());
                    try {
                        Thread.sleep(2000);
                    }catch (InterruptedException e){

                    }
                }
            };
            executorService.execute(runnable);
        }
    }

因爲只有一個唯一線程,所以我們會每2秒執行一個任務,且線程名只有唯一的一個。看下驗證結果。

2019-08-13 15:44:44.175 21796-22542/com.calm.cthreadpool E/CSingleThreadExecutor: CSingleThreadExecutor Start Run: 任務 = 0,線程 = pool-3-thread-1
2019-08-13 15:44:46.177 21796-22542/com.calm.cthreadpool E/CSingleThreadExecutor: CSingleThreadExecutor Start Run: 任務 = 1,線程 = pool-3-thread-1
2019-08-13 15:44:48.180 21796-22542/com.calm.cthreadpool E/CSingleThreadExecutor: CSingleThreadExecutor Start Run: 任務 = 2,線程 = pool-3-thread-1
2019-08-13 15:44:50.180 21796-22542/com.calm.cthreadpool E/CSingleThreadExecutor: CSingleThreadExecutor Start Run: 任務 = 3,線程 = pool-3-thread-1
2019-08-13 15:44:52.182 21796-22542/com.calm.cthreadpool E/CSingleThreadExecutor: CSingleThreadExecutor Start Run: 任務 = 4,線程 = pool-3-thread-1
2019-08-13 15:44:54.185 21796-22542/com.calm.cthreadpool E/CSingleThreadExecutor: CSingleThreadExecutor Start Run: 任務 = 5,線程 = pool-3-thread-1
2019-08-13 15:44:56.186 21796-22542/com.calm.cthreadpool E/CSingleThreadExecutor: CSingleThreadExecutor Start Run: 任務 = 6,線程 = pool-3-thread-1
2019-08-13 15:44:58.188 21796-22542/com.calm.cthreadpool E/CSingleThreadExecutor: CSingleThreadExecutor Start Run: 任務 = 7,線程 = pool-3-thread-1
2019-08-13 15:45:00.190 21796-22542/com.calm.cthreadpool E/CSingleThreadExecutor: CSingleThreadExecutor Start Run: 任務 = 8,線程 = pool-3-thread-1
2019-08-13 15:45:02.191 21796-22542/com.calm.cthreadpool E/CSingleThreadExecutor: CSingleThreadExecutor Start Run: 任務 = 9,線程 = pool-3-thread-1

可以看到與我們預判一致,沒隔2秒執行一個任務,執行的線程名爲thread-1

 

以上4種方式 就是我們線程池的常規使用方案,在實際項目中我們可以根據實際場景來擇優使用。

示例相關代碼:https://gitee.com/calm1516/CThreadPool.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章