Java併發編程筆記6:線程池的使用

ThreadPoolExecutor

在 Executoors 中的 newChachedThreadPool, newFixedThreadPool, newScheduledThreadExecutor 的工廠方法返回的都是 ThreadPoolExecutor 對象。若是默認的執行策略不能知足需求,能夠經過 ThreadPoolExecutor 的構造函數進行實例化,根據本身的需求定製。 html

)

ThreadPoolExecutor(int corePoolSize,//線程池基本大小
                   int maximumPoolSize, //線程池最大尺寸
                   long keepAliveTime, //線程空閒後的存活時間
                   TimeUnit unit, 
                   BlockingQueue<Runnable> workQueue, //任務隊列
                   ThreadFactory threadFactory, //線程工廠 
                   RejectedExecutionHandler handler) //飽和策略
複製代碼

線程建立和銷燬

  • corePoolSize是線程池的基本大小,即在沒有任務執行時線程池的大小。
    • 在建立了線程池後,默認狀況下,線程池中並無任何線程,而是等待有任務到來才建立線程去執行任務。
    • 能夠調用prestartAllCoreThreads()或者prestartCoreThread()方法預建立線程,即在沒有任務到來以前就建立corePoolSize個線程或者一個線程。
    • 默認狀況下,在建立了線程池後,線程池中的線程數爲0,當有任務來以後,就會建立一個線程去執行任務,當線程池中的線程數目達到corePoolSize後,就會把到達的任務放到緩存隊列當中
    • 在工做隊列滿了的狀況下才會建立超出這個數量的線程。
  • maximumPoolSize是線程池的最大尺寸,表示能夠同時活動的線程數量的上限。
  • keepAliveTime 和 unit 共同表示了線程空閒後的存活時間
    • 默認狀況下,只有當線程池中的線程數大於corePoolSize時,keepAliveTime纔會起做用,直到線程池中的線程數不大於corePoolSize。也就是當線程池中的線程數大於corePoolSize時,若是一個線程空閒的時間達到keepAliveTime,則會終止,直到線程池中的線程數不超過corePoolSize。
    • 若是調用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數不大於corePoolSize時,keepAliveTime參數也會起做用,直到線程池中的線程數爲0

newFixedThreadPool 工廠方法將線程池的基本大小和最大大小都設置爲參數中指定的值,並且建立的線程池不會超時。java

newCachedThreadPool工廠方法將線程池的最大大小設置爲Integer.MAX_VALUE,將基本大小設置爲0,並將超時設置爲1分鐘,這種方法建立出來的線程池能夠被無限擴展,而且當需求下降時會自動收縮。git

管理隊列任務

使用BlokcingQueue來保存等待執行的任務。基本的隊列有無界隊列,有界隊列和同步移交。隊列的選擇和線程池的其餘配置參數有關編程

newFixedThreadPool 和 newSingleThreadExecutor 在默認狀況下使用一個無界的LinkedBlockingQueue。若是全部工做者線程都處於忙碌狀態, 那麼任務將在隊列中等待。緩存

有界隊列包括ArrayBlockingQueue以及有界的LinkedBlockingQueue和PriorityBlockingQueue。在使用有界隊列時,隊列的大小須要和線程池的大小一塊兒調節。線程池小而隊列較大,有助於減小內存使用量,下降CPU的使用率,同時還能夠減小上下文切換,可是可能會限制吞吐量。併發

對於很是大或無界的線程池,能夠經過SynchronousQueue來避免任務排隊,以及直接將任務從生產者移交給工做者線程。這個隊列的put方法會阻塞,直到有線程準備從隊列裏面take,因此本質上SynchronousQueue並非Queue,它不存儲任何東西,它只是在移交東西,是一種在線程之間進行移交的機制。要將一個任務放到其中,必須有另外一個線程正在等待接受這個元素。若是沒有線程正在等待,而且線程池的當前大小小於最大值,那麼ThreadPoolExecutor將建立一個新的線程,不然這個任務獎盃拒絕。在 newCachedThreadPool中採用了SynchronousQueue。函數

飽和策略

當有界對壘被填滿後,飽和策略開始發揮做用。經過setRejectedExecutionHandler來修改。有如下四種飽和策略。spa

  • AbortPolicy: 飽和策略,使用這種策略的線程池,將在沒法繼續接受新任務時,給任務提交方拋出RejectedExecutionException,讓他們決定要如何處理
  • DiscardPolicy:拋棄策略,直接丟棄掉新來的任務
  • CallerRunsPolicy:調用者運行策略,這個策略,顧名思義,將把任務交給調用方所在的線程去執行
  • Discard-OldestPolicy: 拋棄最舊的策略,拋棄下一個獎盃執行的任務,而後嘗試從新提交新的任務。(若是是優先級隊列,會拋棄優先級最高的任務,最好不要一塊兒使用)

線程工廠

線程池在建立線程時,經過線程工廠方法來完成。在默認的ThreadFactory接口中只定義了一個方法newThread,每當建立新線程時都會調用這個方法。能夠本身建立一個類實現默認的ThreadFactory接口來定製本身的線程工廠。線程

擴展ThreadPoolExecutor

ThreadPoolExecutor是能夠擴展的,它提供了幾個能夠在子類中改寫的方法:beforeExecute, afterExecute, terminated。在執行任務的線程中將調用beforeExecute和afterExecute方法。不管是正常返回仍是拋出異常,afterExecute都被調用。若是beforeExecute拋出一個RuntimeException,任務將不被執行,afterExecute也不會調用。rest

參考資料

相關文章
相關標籤/搜索