Android高并發問題處理和線程池ThreadPool線程池源碼分析

Android實現高性能,高并發,可延時線程池管理

為什么要使用線程池?

1.)new Thread()的缺點

每次new Thread()耗費性能
調用new Thread()創建的線程缺乏管理,被稱為野線程,而且可以無限制創建,之間相互競爭,會導致過多占用系統資源導致系統癱瘓。
不利于擴展,比如如定時執行、定期執行、線程中斷
2.)采用線程池的優點

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

線程池相關類的繼承關系:

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)
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);
            }
        }

    }

}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容