網絡訪問頻繁的項目---ThreadManager(線程池管理類)

一、先了解ThreadPoolExecutor這個類。

線程池ThreadPoolExecutor繼承自ExecutorService.是jdk1.5加入的新特性,將提交執行的任務在內部線程池中的可用線程中執行。
構造函數
  
ThreadPoolExecutor(int corePoolSize, 
                              int maximumPoolSize, 
                              long keepAliveTime, 
                              TimeUnit unit, 
                              BlockingQueue<Runnable> workQueue, 
                              ThreadFactory threadFactory, 
                              RejectedExecutionHandler handler)

   (一)瞭解一個常用變量

                corePoolSize:線程池維護線程的最少數量.
                maximumPoolSize:線程池維護線程的最大數量
                keepAliveTime :線程池維護線程所允許的空閒時間
                unit:線程池維護線程所允許的空閒時間的單位
                workQueue: 線程池所使用的緩衝隊列
                handler: 線程池對拒絕任務的處理策略
      一個任務通過 execute(Runnable)方法被添加到線程池,任務就是一個 Runnable類型的對象,任務的執行方法就是Runnable類型對象的run()方法。
      當一個任務通過execute(Runnable)方法欲添加到線程池時:

      l  如果此時線程池中的數量小於corePoolSize,即使線程池中的線程都處於空閒狀態,也要創建新的線程來處理被添加的任務。

      l  如果此時線程池中的數量等於 corePoolSize,但是緩衝隊列 workQueue未滿,那麼任務被放入緩衝隊列。

      l  如果此時線程池中的數量大於corePoolSize,緩衝隊列workQueue滿,並且線程池中的數量小於maximumPoolSize,建新的線程來處理被添加的任務。

      l  如果此時線程池中的數量大於corePoolSize,緩衝隊列workQueue滿,並且線程池中的數量等於maximumPoolSize,那麼通過 handler所指定的策略來處理此任務。也就是:處理任務的優先級爲:核心線程corePoolSize、任務隊列workQueue、最大線程maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務。

     l  當線程池中的線程數量大於 corePoolSize時,如果某線程空閒時間超過keepAliveTime,線程將被終止。這樣,線程池可以動態的調整池中的線程數。


ThreadPoolExecutor配置

一、ThreadPoolExcutor爲一些Executor提供了基本的實現,這些Executor是由Executors中的工廠 newCahceThreadPool、newFixedThreadPool和newScheduledThreadExecutor返回的。 ThreadPoolExecutor是一個靈活的健壯的池實現,允許各種各樣的用戶定製。

二、線程的創建與銷燬

1、核心池大小、最大池大小和存活時間共同管理着線程的創建與銷燬。

2、核心池的大小是目標的大小;線程池的實現試圖維護池的大小;即使沒有任務執行,池的大小也等於核心池的大小,並直到工作隊列充滿前,池都不會創建更多的線程。如果當前池的大小超過了核心池的大小,線程池就會終止它。

3、最大池的大小是可同時活動的線程數的上限。

4、如果一個線程已經閒置的時間超過了存活時間,它將成爲一個被回收的候選者。

5、newFixedThreadPool工廠爲請求的池設置了核心池的大小和最大池的大小,而且池永遠不會超時

6、newCacheThreadPool工廠將最大池的大小設置爲Integer.MAX_VALUE,核心池的大小設置爲0,超時設置爲一分鐘。這樣創建了無限擴大的線程池,會在需求量減少的情況下減少線程數量。

三、管理

1、 ThreadPoolExecutor允許你提供一個BlockingQueue來持有等待執行的任務。任務排隊有3種基本方法:無限隊列、有限隊列和同步移交。

2、 newFixedThreadPool和newSingleThreadExectuor默認使用的是一個無限的 LinkedBlockingQueue。如果所有的工作者線程都處於忙碌狀態,任務會在隊列中等候。如果任務持續快速到達,超過了它們被執行的速度,隊列也會無限制地增加。穩妥的策略是使用有限隊列,比如ArrayBlockingQueue或有限的LinkedBlockingQueue以及 PriorityBlockingQueue。

3、對於龐大或無限的池,可以使用SynchronousQueue,完全繞開隊列,直接將任務由生產者交給工作者線程

4、可以使用PriorityBlockingQueue通過優先級安排任務


項目中一個線程池管理類,提供三個線程池

public class ThreadManager {
    public static final String DEFAULT_SINGLE_POOL_NAME = "DEFAULT_SINGLE_POOL_NAME";

    private static ThreadPoolProxy mLongPool = null;
    private static Object mLongLock = new Object();

    private static ThreadPoolProxy mShortPool = null;
    private static Object mShortLock = new Object();

    private static ThreadPoolProxy mDownloadPool = null;
    private static Object mDownloadLock = new Object();

    private static Map<String, ThreadPoolProxy> mMap = new HashMap<String, ThreadPoolProxy>();
    private static Object mSingleLock = new Object();

    // private static ThreadPoolProxy

    /** 獲取下載線程 */
    public static ThreadPoolProxy getDownloadPool() {
        synchronized (mDownloadLock) {
            if (mDownloadPool == null) {
                mDownloadPool = new ThreadPoolProxy(3, 3, 5L);
            }
            return mDownloadPool;
        }
    }

    /**
     * 獲取一個用於執行長耗時任務的線程池,避免和短耗時任務處在同一個隊列 而阻塞了重要的短耗時的任務,通常用聯網操作s
     */
    public static ThreadPoolProxy getLongPool() {
        synchronized (mLongLock) {
            if (mLongPool == null) {
                mLongPool = new ThreadPoolProxy(5, 5, 5L);
            }
            return mLongPool;
        }
    }

    /** 獲取一個用於執行短耗時任務的線程池,避免因爲和耗時長的任務處在同一個隊列而長時間得不到執行,通常用來執行本地的IO/SQL */
    public static ThreadPoolProxy getShortPool() {
        synchronized (mShortLock) {
            if (mShortPool == null) {
                mShortPool = new ThreadPoolProxy(2, 2, 5L);
            }
            return mShortPool;
        }
    }

    /** 獲取一個單線程池,所有任務將會被按照加入的順序執行,免除了同步開銷的問題 */
    public static ThreadPoolProxy getSinglePool() {
        return getSinglePool(DEFAULT_SINGLE_POOL_NAME);
    }

    /** 獲取一個單線程池,所有任務將會被按照加入的順序執行,免除了同步開銷的問題 */
    public static ThreadPoolProxy getSinglePool(String name) {
        synchronized (mSingleLock) {
            ThreadPoolProxy singlePool = mMap.get(name);
            if (singlePool == null) {
                singlePool = new ThreadPoolProxy(1, 1, 5L);
                mMap.put(name, singlePool);
            }
            return singlePool;
        }
    }

    public static class ThreadPoolProxy {
        private ThreadPoolExecutor mPool;
        private int mCorePoolSize; //線程池維護線程的最少數量
        private int mMaximumPoolSize; //線程池維護線程的最大數量
        private long mKeepAliveTime; //線程池維護線程所允許的空閒時間

        private ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long keepAliveTime) {
            mCorePoolSize = corePoolSize;
            maximumPoolSize = maximumPoolSize;
            mKeepAliveTime = keepAliveTime;
        }

        // 執行任務,當線程池處於關閉,將會重新創建的線程池
        public synchronized void execute(Runnable runn) {
            if (runn == null) {
                return;
            }
            if (mPool == null || mPool.isShutdown()) {
                // 參數說明
                // 當線程池中的線程小於mCorePoolSize,直接創建新的線程加入線程池執行任務
                // 當線程池中的線程數目等於mCorePoolSize,將會把任務放入任務隊列BlockingQueue中
                // 當BlockingQueue中的任務放滿了,將會創建新的線程去執行,
                // 但是當總線程數大於mMaximumPoolSize時,將會拋出異常,交給RejectedExecutionHandler處理
                // mKeepAliveTime是線程執行完任務後,且隊列中沒有可以執行的任務,存活的時間,後面的參數是時間單位
                // ThreadFactory是每次創建新的線程工廠
                mPool = new ThreadPoolExecutor(mCorePoolSize,//
                        mMaximumPoolSize, mKeepAliveTime,//
                        TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
                        Executors.defaultThreadFactory(), new AbortPolicy());
            }
            mPool.execute(runn);
        }

        /** 取消線程池中某個還未執行的任務 */
        public synchronized void cancel(Runnable runn) {
            if (mPool != null && (!mPool.isShutdown()) || mPool.isTerminating()) {
                mPool.getQueue().remove(runn);
            }
        }

        /** 取消線程池中某個還未執行的任務 */
        public synchronized boolean contains(Runnable runn) {
            if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
                return mPool.getQueue().contains(runn);
            } else {
                return false;
            }
        }

        /** 立刻關閉線程池,並且正在執行的任務也將會被中斷 */
        public void stop() {
            if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
                mPool.shutdown();
            }
        }

        /** 平緩關閉單任務線程池,但是會確保所有已經加入的任務都將會被執行完畢才關閉 */
        public synchronized void shutdown() {
            if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) {
                mPool.shutdownNow();
            }
        }
    }
}



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