java 線程池使用和詳解

線程池的使用

構造方法javascript

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
  • corePoolSize:線程池維護線程的最少數量
  • maximumPoolSize:線程池維護線程的最大數量
  • keepAliveTime:線程池維護線程所容許的空閒時間
  • unit:線程池維護線程所信息的空閒時間的單位
  • workQueue:線程池所使用的緩衝隊列
  • threadFactory:線程建立工廠類
  • handler:線程池對任務的處理策略

注意

  • 線程池在建立的時候是不建立線程的,只有加入任務才建立線程,固然能夠調用prestartCoreThread方法(是在ThreadPoolExecutor類中實現的)來初始化一個線程。
  • 線程池先會建立完corePoolSize個線程,在把任務保存到隊列中,隊列滿後纔會再建立線程,直到規定的maximumPoolSize,而後會執行拒絕策略。
  • 設置線程池的大小參考
    • 若是是CPU密集型任務,就須要儘可能壓榨CPU,參考值能夠設爲 NCPU+1
    • 若是是IO密集型任務,參考值能夠設置爲2*NCPU

BlockingQueue經常使用的3個實現類java

  1. ArrayBlockingQueue 構造參數必須帶一個int參數來指明其大小,FIFO
  2. LinkedBlockingQuene 大小不定,能夠人爲指定,若沒有有Integer.MAX_VALUE來決定。FIFO
  3. SynchronousQueue 對其操做必須放和取交替完成。在線程池中它不會保存提交的任務,而是將直接新建一個線程來執行新來的任務

LinkedBlockingQueue的數據吞吐量要大於ArrayBlockingQueue,但在線程數量很大時其性能的可預見性低於ArrayBlockingQueue. SynchronousQueue初始化後必須先有其餘線程對其使用take()方法後才能使用put() 或者 offer()方法微信

java 定義好的4中類型的線程池

  1. newCachedThreadPool建立一個可緩衝線程池,若是線程池長度超過處理須要,可靈活回收空閒線程,若無可用線程,則新建線程
  2. newFixedThreadPool建立一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。
  3. newScheduledThreadPool 建立一個定長線程池,支持定時和週期性任務執行。
  4. newSingleThreadExecutor 一個單線程化的線程池,確保全部任務按照指定的順序執行。

下面是線程池核心的執行代碼,只看懂一點:cry:併發

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        //它在執行完一個線程會getTask再去取一個,直到沒有任務。
        while (task != null || (task = getTask()) != null) {
            w.lock();
            //.......刪除N行代碼
            try {
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

gettask方法性能

private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            //......省略N行代碼

            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

這裏用到了BlockingQueue的方法,很巧妙的使用。timed是判斷這個線程是否能夠回收,由咱們設置的allowCoreThreadTimeOut和當前線程池線程大小決定的。當要回收,用的是poll方法,不能回收用的是take方法阻塞線程線程

線程池的shutdown()和shutdownNow();

  • shutdown()方法會更改線程池的狀態爲SHUTDOWN狀態,並不會當即終止。此時不能往線程池中添加任務,不然會拋出RejectedExecutionException異常。它會等線程池裏的全部任務都處理完畢再退出線程。
  • shutdownNow()方法會當即更改狀態爲STOP狀態。並試圖中止全部正在執行的線程,再也不處理還在池隊列中等待的任務,它會返回那些未執行的任務。其試圖終止線程的方法是經過調用Thread.interrupt()方法來實現的。

提個問題,線程池有兩種提交方式execute()和submit()區別,能夠在評論區討論哦!請關注微信公衆號,查看,嘻嘻。不過之後會在評論區回覆的!!rest


歡迎關注個人微信公衆號cobs-snail,讓咱們一塊兒前進吧!!code

前進吧蝸牛

相關文章
相關標籤/搜索