ThreadPoolExecutor 引數解析

whywhy發表於2018-01-24

ThreadPoolExecutor 主要有以下幾個引數:

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

引數說明

corePoolSize 核心執行緒數量

  • 即使沒有任務執行,核心執行緒也會一直存活
  • 執行緒數小於核心執行緒時,即使有空閒執行緒,執行緒沲也會建立新執行緒執行任務
  • 設定allowCoreThreadTimeout=true時,核心執行緒會超時關閉

maximumPoolSize 最大執行緒數

  • 當所有核心執行緒都在執行任務,且任務佇列已滿時,執行緒沲會建立新執行緒執行任務
  • 當執行緒數=maxPoolSize,且任務佇列已滿,此時新增任務時會觸發RejectedExecutionHandler進行處理

keepAliveTime TimeUnit 執行緒空閒時間

  • 如果執行緒數>corePoolSize,且有執行緒空閒時間達到keepAliveTime時,執行緒會銷燬,直到執行緒數量=corePoolSize
  • 如果設定allowCoreThreadTimeout=true時,核心執行緒執行完任務也會銷燬直到數量=0

workQueue 任務佇列

  • ArrayBlockingQueue 有界佇列,需要指定佇列大小
  • LinkedBlockingQueue 若指定大小則和ArrayBlockingQueue類似,若不指定大小則預設能儲存Integer.MAX_VALUE個任務,相當於無界佇列,此時maximumPoolSize值其實是無意義的
  • SynchronousQueue 同步阻塞佇列,當有任務新增進來後,必須有執行緒從佇列中取出,當前執行緒才會被釋放,newCachedThreadPool就使用這種佇列

ThreadFactory 建立執行緒的工廠

  • 通過他可以建立執行緒時做一些想做的事,比如自定義執行緒名稱:
private static class CustomThreadFactory implements ThreadFactory {
        private final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        CustomThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            namePrefix = "ume-pool-" + POOL_NUMBER.getAndIncrement() + "-thread-";
        }

        @Override
        public Thread newThread(@NonNull Runnable runnable) {
            Thread thread = new Thread(group, runnable, namePrefix + threadNumber.getAndIncrement(), 0);
            if (thread.isDaemon()) {
                thread.setDaemon(false);
            }

            if (thread.getPriority() != Thread.NORM_PRIORITY) {
                thread.setPriority(Thread.NORM_PRIORITY);
            }

            return thread;
        }
    }
複製程式碼

RejectedExecutionHandler 執行緒數和佇列都滿的情況下,對新新增的任務的處理方式

  • AbortPolicy 直接丟擲異常
  • CallerRunsPolicy 直接呼叫新新增runnable.run函式執行任務
  • DiscardPolicy 直接拋棄任務,什麼也不幹
  • DiscardOldestPolicy 拋棄佇列中最先加入的任務,然後再新增新任務

下面是自定義實現,相當於DiscardPolicy,只列印異常資訊

    private static class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
        private CustomRejectedExecutionHandler() {
        }
        
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            Log.e("umeweb", "Task " + r.toString() + " rejected from " + e.toString());
        }
    }
複製程式碼

附上一個自己在用的簡單執行緒沲實現

 private final ThreadPoolExecutor mExecutor;

    private ThreadPoolManager() {
        final int cpu = Runtime.getRuntime().availableProcessors();
        final int corePoolSize = cpu + 1;
        final int maximumPoolSize = cpu * 2 + 1;
        final long keepAliveTime = 1L;
        final TimeUnit timeUnit = TimeUnit.SECONDS;
        final int maxQueueNum = 128;

        mExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                timeUnit,
                new LinkedBlockingQueue<Runnable>(maxQueueNum),
                new CustomThreadFactory(),
                new CustomRejectedExecutionHandler());
    }

    public void executor(@NonNull Runnable runnable) {
        mExecutor.execute(runnable);
    }
複製程式碼

相關文章