併發處理規則最佳推薦
企業在架構設計時,都會遇到併發處理的問題。其實,解決併發問題,並不是難事,只要做到有章可循。以下是某網際網路企業的最佳實踐總結,僅供參考。
Rule 1. 【強制】建立執行緒或執行緒池時請指定有意義的執行緒名稱,方便出錯時回溯。
1)建立單條執行緒時直接指定執行緒名稱
2) 執行緒池則使用guava或自行封裝的ThreadFactory,指定命名規則。
Rule 2. 【推薦】儘量使用執行緒池來建立執行緒
除特殊情況,儘量不要自行建立執行緒,更好的保護執行緒資源。
同理,定時器也不要使用Timer,而應該使用ScheduledExecutorService。
因為Timer只有單執行緒,不能併發的執行多個在其中定義的任務,而且如果其中一個任務丟擲異常,整個Timer也會掛掉,而ScheduledExecutorService只有那個沒捕獲到異常的任務不再定時執行,其他任務不受影響。
Rule 3. 【強制】執行緒池不允許使用 Executors去建立,避資源耗盡風險
Executors返回的執行緒池物件的弊端 :
1)FixedThreadPool 和 SingleThreadPool:
允許的請求佇列長度為 Integer.MAX_VALUE,可能會堆積大量的請求,從而導致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允許的建立執行緒數量為 Integer.MAX_VALUE,可能會建立大量的執行緒,從而導致 OOM。
應透過 new ThreadPoolExecutor(xxx,xxx,xxx,xxx)這樣的方式,更加明確執行緒池的執行規則,合理設定Queue及執行緒池的core size和max size,建議使用vjkit封裝的ThreadPoolBuilder。
Rule 4. 【強制】正確停止執行緒
Thread.stop()不推薦使用,強行的退出太不安全,會導致邏輯不完整,操作不原子,已被定義成Deprecate方法。
停止單條執行緒,執行Thread.interrupt()。
停止執行緒池:
ExecutorService.shutdown(): 不允許提交新任務,等待當前任務及佇列中的任務全部執行完畢後退出;
ExecutorService.shutdownNow(): 透過Thread.interrupt()試圖停止所有正在執行的執行緒,並不再處理還在佇列中等待的任務。
最優雅的退出方式是先執行shutdown(),再執行shutdownNow(),vjkit的ThreadPoolUtil進行了封裝。
注意,Thread.interrupt()並不保證能中斷正在執行的執行緒,需編寫可中斷退出的Runnable,見規則5。
Rule 5. 【強制】編寫可停止的Runnable
執行Thread.interrupt()時,如果執行緒處於sleep(), wait(), join(), lock.lockInterruptibly()等blocking狀態,會丟擲InterruptedException,如果執行緒未處於上述狀態,則將執行緒狀態設為interrupted。
因此,如下的程式碼無法中斷執行緒:
5.1 正確處理InterruptException
因為InterruptException異常是個必須處理的Checked Exception,所以run()所呼叫的子函式很容易吃掉異常並簡單的處理成列印日誌,但這等於停止了中斷的傳遞,外層函式將收不到中斷請求,繼續原有迴圈或進入下一個堵塞。
正確處理是呼叫Thread.currentThread().interrupt(); 將中斷往外傳遞。
5.2 主迴圈及進入阻塞狀態前要判斷執行緒狀態
其他如Thread.sleep()的程式碼,在正式sleep前也會判斷執行緒狀態。
Rule 6. 【強制】Runnable中必須捕獲一切異常
如果Runnable中沒有捕獲RuntimeException而向外丟擲,會發生下列情況:
1) ScheduledExecutorService執行定時任務,任務會被中斷,該任務將不再定時排程,但執行緒池裡的執行緒還能用於其他任務。
2) ExecutorService執行任務,當前執行緒會中斷,執行緒池需要建立新的執行緒來響應後續任務。
3) 如果沒有在ThreadFactory設定自定義的UncaughtExceptionHanlder,則異常最終只列印在System.err,而不會列印在專案的日誌中。
因此建議自寫的Runnable都要保證捕獲異常; 如果是第三方的Runnable,可以將其再包裹一層vjkit中的SafeRunnable。
Rule 7. 【強制】全域性的非執行緒安全的物件可考慮使用ThreadLocal存放
全域性變數包括單例物件,static成員變數。
著名的非執行緒安全類包括SimpleDateFormat,MD5/SHA1的Digest。
對這些類,需要每次使用時建立。
但如果建立有一定成本,可以使用ThreadLocal存放並重用。
ThreadLocal變數需要定義成static,並在每次使用前重置。
Rule 8. 【推薦】縮短鎖
1) 能鎖區塊,就不要鎖整個方法體;
2)能用物件鎖,就不要用類鎖。
Rule 9. 【推薦】選擇分離鎖,分散鎖甚至無鎖的資料結構
分離鎖:
1) 讀寫分離鎖ReentrantReadWriteLock,讀讀之間不加鎖,僅在寫讀和寫寫之間加鎖;
2) Array Base的queue一般是全域性一把鎖,而Linked Base的queue一般是隊頭隊尾兩把鎖。
分散鎖(又稱分段鎖):
1)如JDK7的ConcurrentHashMap,分散成16把鎖;
2)對於經常寫,少量讀的計數器,推薦使用JDK8或vjkit封裝的LongAdder物件效能更好(內部分散成多個counter,減少樂觀鎖的使用,取值時再相加所有counter)
無鎖的資料結構:
1)完全無鎖無等待的結構,如JDK8的ConcurrentHashMap;
2)基於CAS的無鎖有等待的資料結構,如AtomicXXX系列。
Rule 10. 【推薦】基於ThreadLocal來避免鎖
比如Random例項雖然是執行緒安全的,但其實它的seed的訪問是有鎖保護的。因此建議使用JDK7的ThreadLocalRandom,透過在每個執行緒裡放一個seed來避免了加鎖。
Rule 11. 【推薦】規避死鎖風險
對多個資源多個物件的加鎖順序要一致。
如果無法確定完全避免死鎖,可以使用帶超時控制的tryLock語句加鎖。
Rule 12. 【推薦】volatile修飾符,AtomicXX系列的正確使用
多執行緒共享的物件,在單一執行緒內的修改並不保證對所有執行緒可見。使用volatile定義變數可以解決(解決了可見性)。
但是如果多條執行緒併發進行基於當前值的修改,如併發的counter++,volatile則無能為力(解決不了原子性)。
此時可使用Atomic*系列:
但如果需要原子地同時對多個AtomicXXX的Counter進行操作,則仍然需要使用synchronized將改動程式碼塊加鎖。
Rule 13. 【推薦】延時初始化的正確寫法
透過雙重檢查鎖(double-checked locking)實現延遲初始化存在隱患,需要將目標屬性宣告為volatile型,為了更高的效能,還要把volatile屬性賦予給臨時變數,寫法複雜。
所以如果只是想簡單的延遲初始化,可用下面的靜態類的做法,利用JDK本身的class載入機制保證唯一初始化。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31545808/viewspace-2218094/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Prometheus監控規則推薦網站🔰Prometheus網站
- 系統單據號生成規則推薦
- Postgres併發處理
- MySQL 併發處理MySql
- 處理併發衝突
- 資料的集合處理,有哪些規則?
- 併發問題處理方式
- 電影推薦系統資料預處理
- 聊聊介面最大併發處理數
- 前端優化之高併發處理前端優化
- 海量資料的併發處理
- 理解 Nginx 在處理請求時的匹配規則Nginx
- 推薦6個高效的語言處理Python庫Python
- SQL最佳化 | MySQL問題處理案例分享三則MySql
- 【翻譯】2021 年最佳 Linux 發行版推薦Linux
- Go 併發 2.2:錯誤處理模式Go模式
- Entity Framework Core中的併發處理Framework
- ElasticSearch 文件併發處理以及文件路由Elasticsearch路由
- 使用Fan-Out模式併發處理模式
- Go併發呼叫的超時處理Go
- SQLite 併發的四種處理方式SQLite
- Spring如何處理執行緒併發Spring執行緒
- 直播系統,利用關聯規則實現推薦演算法演算法
- 【推薦】超好用的Linux文字文書處理軟體!Linux
- [Python影像處理] 三十.影像量化及取樣處理萬字詳細總結(推薦)Python
- 轉載:Java處理高併發量訪問的處理總結Java
- Apache Tomcat如何高併發處理請求ApacheTomcat
- 處理高併發的一般思路
- 高併發實戰之冪等處理
- 專業的模型後處理軟體推薦:SimLab Composer 10模型
- Go語言(golang)的錯誤(error)處理的推薦方案GolangError
- 鐳射雷達常用的資料處理軟體推薦
- 推特大規模應用的流處理框架:Apache Heron框架Apache
- 學習Hadoop最佳書籍推薦Hadoop
- Golang 推薦的命名規範Golang
- Spring Cloud 開發的一些推薦規劃SpringCloud
- Java併發---併發理論Java
- 如何處理系統具有較大併發量?