JAVA併發編程總結

.1.       不應用線程池的缺點

有些開發者圖省事,遇到需要多線程處理的地方,直接new Thread(...).start(),對於一般場景是沒問題的,但如果是在併發請求很高的情況下,就會有些隱患:

·       新建線程的開銷。線程雖然比進程要輕量許多,但對於JVM來說,新建一個線程的代價還是挺大的,決不同於新建一個對象

·       資源消耗量。沒有一個池來限制線程的數量,會導致線程的數量直接取決於應用的併發量,這樣有潛在的線程數據巨大的可能,那麼資源消耗量將是巨大的

·       穩定性。當線程數量超過系統資源所能承受的程度,穩定性就會成問題

.2.       制定執行策略

在每個需要多線程處理的地方,不管併發量有多大,需要考慮線程的執行策略

·       任務以什麼順序執行

·       可以有多少個任務併發執行

·       可以有多少個任務進入等待執行隊列

·       系統過載的時候,應該放棄哪些任務?如何通知到應用程序?

·       一個任務的執行前後應該做什麼處理

.3.       線程池的類型

不管是通過Executors創建線程池,還是通過Spring來管理,都得清楚知道有哪幾種線程池:

·       FixedThreadPool:定長線程池,提交任務時創建線程,直到池的最大容量,如果有線程非預期結束,會補充新線程

·       CachedThreadPool:可變線程池,它猶如一個彈簧,如果沒有任務需求時,它回收空閒線程,如果需求增加,則按需增加線程,不對池的大小做限制

·       SingleThreadExecutor:單線程。處理不過來的任務會進入FIFO隊列等待執行

·       SecheduledThreadPool:週期性線程池。支持執行週期性線程任務

其實,這些不同類型的線程池都是通過構建一個ThreadPoolExecutor來完成的,所不同的是corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory這麼幾個參數。具體可以參見JDK DOC

.4.       線程池飽和策略

由以上線程池類型可知,除了CachedThreadPool其他線程池都有飽和的可能,當飽和以後就需要相應的策略處理請求線程的任務,比如,達到上限時通過ThreadPoolExecutor.setRejectedExecutionHandler方法設置一個拒絕任務的策略,JDK提供了AbortPolicyCallerRunsPolicyDiscardPolicyDiscardOldestPolicy幾種策略,具體差異可見JDK DOC

.5.       線程無依賴性

多線程任務設計上儘量使得各任務是獨立無依賴的,所謂依賴性可兩個方面:

·       線程之間的依賴性。如果線程有依賴可能會造成死鎖或飢餓

·       調用者與線程的依賴性。調用者得監視線程的完成情況,影響可併發量

當然,在有些業務裏確實需要一定的依賴性,比如調用者需要得到線程完成後結果,傳統的Thread是不便完成的,因爲run方法無返回值,只能通過一些共享的變量來傳遞結果,但在Executor框架裏可以通過FutureCallable實現需要有返回值的任務,當然線程的異步性導致需要有相應機制來保證調用者能等待任務完成,關於FutureCallable的用法前文已講解;

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