Executor以及線程池

在應用程序中,老是會出現大量的任務,包括相同類型的和不一樣類型的。要快速處理這些任務,常見方法就是利用多線程,可是也不可能爲每一個任務都建立一個線程,這樣內存也不夠,而且線程的建立銷燬開銷很大。最好是少許線程處理大量任務,實現線程的複用,Executor乾的就是這事。程序只須要把任務提交給Executor,由Executor來肯定怎麼來執行這個任務,即執行策略。Executor的關閉很重要,若是Executor若是沒有關閉,那JVM將沒法結束。關閉方法有shutdown,shutdownNow,shutdown方法執行平緩關閉,若該任務沒有提交則拒絕提交,若該任務已經提交可是沒有執行,將等待它執行完成,若該任務已經執行將等待它執行完成。shutdownNow是粗暴關閉,取消如今執行的任務,拒絕處理新任務,再也不啓動線程池隊列中已提交的任務。當全部已經提交到Executor的任務都執行完成時,Executor將進入terminatede終止狀態。網絡

線程池的底層原理:數據結構:線程池管理器(ThreadpoolFactory),worker,任務隊列Blockqueue;線程池的調度:新提交一個任務時,全部看下現有的線程數量是否是達到了corepoolSize,若是沒有將新建一個線程thread,該線程將執行該任務,當該任務執行完成時,它會去任務隊列中取出任務而後執行任務。若當前線程的數量大於corepoolSize小於maxpoolSize,則看下任務隊列是否已經滿了,若滿了則新建線程thread,若沒有滿則將任務丟到任務隊列中。數據結構

任務的取消和關閉多線程

建設一個任務執行到一半,程序想取消這個任務,那怎麼辦呢?最好的方法是由每一個任務本身來決定如何取消本身,這將保持數據的一致性,不會亂。常見的方法是輪詢一個取消標誌位,當該標誌位被設立了,則執行本身的取消策略。這種方式會有個弊端,當執行該任務的線程因爲某種緣由被阻塞掉,那它將看不到標誌位的設立,這個時候將加入中斷Interrupted。當調用Thread.interrupted()時,線程的中斷標誌位會被設立,阻塞方法會檢查中斷標誌位,將發現中斷標誌位爲true時,將結束阻塞,重置中斷位,提早返回並拋出中斷異常。中斷處理策略:拋出異常(我不想管了,誰愛管誰管),捕獲異常(管了就不能無做爲),恢復中斷位(我想管,我告訴別人我是要中斷的)。說了這麼多如何管理任務的生命週期,最後發現Future已經提供了任務的週期的管理抽象,尷尬。對於不可中斷的阻塞方法(同步io,Selector.select()方法,獲取內置鎖)經過中斷不能達到取消任務的效果,只能特殊處理,好比說關閉socket.close(),拋出中斷異常。當一個線程執行任務時,任務拋出一個未受檢異常。jvm將捕獲到異常,並終止線程,可是對於Executor這樣的服務來講,終止一個線程可能會使它產生影響,因此它捕獲異常並新增一條工做者線程(具體是新增仍是無論看當前的線程數)。雖然這看起來好像沒什麼問題,可是這對於程序來講卻顯的莫名其妙,一個任務無聲無息就取消了。針對這種狀況提供了一個UncaughtExceptionHandler異常捕獲器,線程池能夠爲每一個線程配一個異常捕獲器(經過線程池管理器實現)。jvm

線程池的使用socket

任務的種類比較複雜,爲了更好的利用線程池的優點,對於線程池須要顯示配置,選擇Executors.newFixThreadpool,Executors.newCacheThreadpool,Executors.newSingleThreadpool,Executors.newScheduleThreadExecutor建立不一樣的線程池。選擇哪一種線程池:singleThreadpool線程池能夠更好的同步,當多個任務同時操做一個資源,即便該資源不是同步的,使用singleThreadpool線程池能保證當前任務對狀態的修改能對下一個任務可見。FixThreadpool用於限制任務的數量以保證資源過程問題(網絡操做常見),cacheThreadpool適用於長時間任務和短期任務並行的場景,依賴性任務(會出現線程飢餓)。線程池大小的選擇,計算型密集的任務選擇跟cpu數,IO密集型的根據公式計算(偷個懶,不寫了)。任務隊列的選擇:有界隊列,無界隊列,sychronizedQueue,priorityBlockingQueue。飽和策略的選擇:停止,拋棄,discardOldestPolicy,調用者運行。線程

相關文章
相關標籤/搜索