Android高併發問題處理和執行緒池ThreadPool執行緒池原始碼分析

weixin_34008784發表於2017-06-02

Android實現高效能,高併發,可延時執行緒池管理

為什麼要使用執行緒池?

1.)new Thread()的缺點

每次new Thread()耗費效能
呼叫new Thread()建立的執行緒缺乏管理,被稱為野執行緒,而且可以無限制建立,之間相互競爭,會導致過多佔用系統資源導致系統癱瘓。
不利於擴充套件,比如如定時執行、定期執行、執行緒中斷
2.)採用執行緒池的優點

重用存在的執行緒,減少物件建立、消亡的開銷,效能佳
可有效控制最大併發執行緒數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞
提供定時執行、定期執行、單執行緒、併發數控制等功能

執行緒池相關類的繼承關係:

5468880-c6d8be9125d5a872.jpg
structure.jpg

Executor<--ExecutorService<--AbstractExecutorService<--ThreadPoolExecutor
Executors可以生成快捷的執行緒池,ThreadPoolExecutor完全自定義執行緒池
原始碼ThreadPoolExecutor分析

自定義執行緒池工具ThreadManager(在本文章後面)

    建立了執行緒代理new ThreadPoolProxy()
    作用:替換new Thread()的執行緒
    使用方式:
        ThreadManager.getNormalPool().execute(Runnable物件);//普通執行緒池
        ThreadManager.getDownloadPool().execute(Runnable物件);//下載專用執行緒池
        ThreadManager.getXxxxxPool().remove(Runnable物件);//移除任務(停止執行緒池執行)

使用執行緒池的好處:

1.降低資源消耗:通過重用已經建立的執行緒來降低執行緒建立和銷燬的消耗
2.提高響應速度:任務到達時不需要等待執行緒建立就可以立即執行。
3.提高執行緒的可管理性:執行緒池可以統一管理、分配、調優和監控

原始碼分析:構造方法

public ThreadPoolExecutor(int corePoolSize, //核心執行緒池大小
                          int maximumPoolSize,//執行緒池最大容量大小
                          long keepAliveTime,//執行緒池空閒時,執行緒存活的時間
                          TimeUnit unit,//時間單位
                          BlockingQueue<Runnable> workQueue,//任務佇列
                          ThreadFactory threadFactory,//執行緒工廠
                          RejectedExecutionHandler handler) //執行緒拒絕策略{....}
                         
     //當前的Worker的數量小於核心執行緒池大小時,新建一個Worker。
    if (workerCountOf(c) < corePoolSize) { 
        if (addWorker(command, true))
     (1).corePoolSize:設定一個執行緒池中的核心執行緒數
     如果設定allowCoreThreadTimeOut為false的情況下:
     即使當執行緒池中的執行緒處於空閒狀態,這些執行緒也不會被執行緒池中移除。
     如果設定了allowCoreThreadTimeOut為true,
     那麼當核心執行緒在空閒了一段時間後依舊沒有用於工作,那麼將會從執行緒池中移除。
     注意:(allowCoreThreadTimeOut預設為false,通常情況下也無需做修改)

     (2).maximumPoolSize:執行緒池中所允許建立最大執行緒數量

     (3).keepAliveTime:當執行緒池中的執行緒數量大於核心執行緒數,
     如果這些多出的執行緒在經過了keepAliveTime時間後,
     依然處於空閒狀態,那麼這些多出的空閒執行緒將會被結束其生命週期。

     (4).unit:keepAliveTime的時間單位

     (5).workQueue:執行緒池的快取佇列//用於存放任務的阻塞佇列,當執行緒池中的核心執行緒都處在執行任務時,
     提交的任務將被儲存在workQueue進行緩衝。
     該佇列只能存放通過execute方法提交的Runnable任務。

    (6).threadFactory:執行緒池中用於建立執行緒的工廠
    在這裡使用執行緒工廠的目的也是為了解耦,將建立的實現細節通過工廠進行封裝,
    而不是直接將建立的方式固化在ThreadPoolExecutor本身的程式碼中。
    Thread newThread(Runnable r)

    (7)RejectedExecutionHandler:執行緒池對拒絕任務的處理策略.
    當執行緒池中的執行緒數量達到最大並且阻塞佇列也已經滿了無法再新增任務時,執行緒池所採取的處理策略。

核心方法:addWorker
    addWorker(Runnable firstTask, boolean core)
5468880-f58863cb2a2609de.jpg
ThreadPool02.jpg

總結執行緒池任務提交的過程:

如果執行緒池中實際的執行緒數量小於corePoolSize核心執行緒數,那麼就啟動一個新的執行緒進行任務的處理。
如果執行緒池中實際的執行緒數量大於等於corePoolSize核心核心執行緒數,則將任務放置到任務佇列中進行處理。
如果由於任務佇列已經滿了,無法再存放新的任務,則判斷執行緒池中實際的執行緒數量是否大於maximumPoolSize執行緒池最大容量:
    如果小於,則建立新的執行緒執行.
    否則將拒絕執行任務RejectedExecutionHandler.

ThreadPoolExecutor的其他知識點

關閉執行緒池

兩個方法:shutdownNow()和shutdown().

ThreadPoolExecutor預設有四個拒絕策略

1、ThreadPoolExecutor.AbortPolicy()   直接丟擲異常RejectedExecutionException
2、ThreadPoolExecutor.CallerRunsPolicy()    直接呼叫run方法並且阻塞執行
3、ThreadPoolExecutor.DiscardPolicy()   直接丟棄後來的任務
4、ThreadPoolExecutor.DiscardOldestPolicy()  丟棄在佇列中隊首的任務

官方定義的四種執行緒池

1、FixedThreadPool,數量固定的執行緒池,且任務佇列也沒有大小限制;
        只有核心執行緒,且這裡的核心執行緒也沒有超時限制,因為它不會被回收,所以它能更快的響應
2、CachedThreadPool
    執行緒數量不固定的執行緒池;可以進行自動執行緒回收,只有非核心執行緒,且最大執行緒數為Integer.MAX_VALUE
    適合做大量的耗時較少的任務
3、SingleThreadExecutor
    只有一個核心執行緒,所有任務都在同一執行緒中按序執行,這樣也就不需要處理執行緒同步的問題.
4、ScheduledThreadPool
    它的核心執行緒數量是固定的,而非核心執行緒是沒有限制的,且非核心執行緒空閒時會被回收;適合執行定時任務和具有固定週期的任務

shutdown做了幾件事:

1. 檢查是否能操作目標執行緒
2. 將執行緒池狀態轉為SHUTDOWN
3. 中斷所有空閒執行緒
但是隻是清除一些空閒Worker,並且拒絕新Task加入,對於workQueue中的執行緒還是繼續處理的。

STOP

拒絕所有新Task的加入,同時中斷所有執行緒,WorkerQueue中沒有執行的執行緒全部拋棄。
所以此時Pool是空的,WorkerQueue也是空的

Worker和Task的區別

Worker是當前執行緒池中的執行緒,而task雖然是runnable,但是並沒有真正執行,只是被Worker呼叫了run方法,後面會看到這部分的實現。

maximumPoolSize和corePoolSize的區別:

maximumPoolSize為執行緒池最大容量,也就是說執行緒池最多能起多少Worker。
corePoolSize是核心執行緒池的大小,當corePoolSize滿了時,
同時workQueue full(ArrayBolckQueue是可能滿的) 那麼此時允許新建Worker去處理workQueue中的Task,但是不能超過maximumPoolSize。
超過corePoolSize之外的執行緒會在空閒超時後終止。

最後附上自定義的執行緒池封裝工具ThreadManager

使用方式:
    ThreadManager.getNormalPool().execute(Runnable物件);//普通執行緒池
    ThreadManager.getDownloadPool().execute(Runnable物件);//下載專用執行緒池
    ThreadManager.getXxxxxPool().remove(Runnable物件);//移除任務(停止執行緒池執行)


/**執行緒管理類,管理執行緒池,一個應用中有多個執行緒池,每個執行緒池做自己相關的業務*/
public class ThreadManager {

    private static ThreadPoolProxy mNormalPool = new ThreadPoolProxy(1, 3, 5 * 1000);
    private static ThreadPoolProxy mDownloadPool = new ThreadPoolProxy(3, 3, 5 * 1000);

    public static ThreadPoolProxy getNormalPool() {
        return mNormalPool;
    }

    public static ThreadPoolProxy getDownloadPool() {
        return mDownloadPool;
    }


    public static class ThreadPoolProxy {
        private final int mCorePoolSize;
        private final int mMaximumPoolSize;
        private final long mKeepAliveTime;
        private ThreadPoolExecutor mPool;


        public ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long keepAliveTime) {
            this.mCorePoolSize = corePoolSize;
            this.mMaximumPoolSize = maximumPoolSize;
            this.mKeepAliveTime = keepAliveTime;
        }

        private void initPool() {
            if (mPool == null || mPool.isShutdown()) {
                //                int corePoolSize = 1;//核心執行緒池大小
                //                int maximumPoolSize = 3;//最大執行緒池大小
                //                long keepAliveTime = 5 * 1000;//保持存活的時間
                TimeUnit unit = TimeUnit.MILLISECONDS;//單位
                BlockingQueue<Runnable> workQueue = null;//阻塞佇列

                workQueue = new ArrayBlockingQueue<Runnable>(4);//FIFO,大小有限制
//                workQueue = new LinkedBlockingQueue();//
                //                workQueue = new PriorityBlockingQueue();

                ThreadFactory threadFactory = Executors.defaultThreadFactory();//執行緒工廠

                RejectedExecutionHandler handler = null;//異常捕獲器

                //                handler = new ThreadPoolExecutor.DiscardOldestPolicy();//去掉佇列中首個任務,將新加入的放到佇列中去
                //                handler = new ThreadPoolExecutor.AbortPolicy();//觸發異常
                handler = new ThreadPoolExecutor.DiscardPolicy();//不做任何處理
                //                handler = new ThreadPoolExecutor.CallerRunsPolicy();//直接執行,不歸執行緒池控制,在呼叫執行緒中執行

                //                new Thread(task).start();

                mPool = new ThreadPoolExecutor(mCorePoolSize,
                        mMaximumPoolSize,
                        mKeepAliveTime,
                        unit,
                        workQueue,
                        threadFactory,
                        handler);
            }
        }

        /**
         * 執行任務
         *
         * @param task
         */
        public void execute(Runnable task) {
            initPool();

            //執行任務
            mPool.execute(task);
        }


        public Future<?> submit(Runnable task) {
            initPool();
            return mPool.submit(task);
        }

        public void remove(Runnable task) {
            if (mPool != null && !mPool.isShutdown()) {
                mPool.getQueue()
                        .remove(task);
            }
        }

    }

}

相關文章