一、性能和思考
前言:使用併發的目的是要提高性能,引入多線程之後,其實會帶來其他額外開銷,如線程間的協作、增加的上下文的切換、線程的創建和銷燬、線程的調度等等。過度的或對多線程的使用不當會導致多線程甚至沒有多線程的效率高。
衡量應用程序性能的標準:
服務時間、延遲時間(多塊)、吞吐量(處理能力的指標、完成工作的多少)、可伸縮性等。對於服務器應用程序:可伸縮性、吞吐量這個方面往往是比較看重的。
開發應用時的思路:
- 先確保程序正確性、確實達不到期望的效果時,再提高速度,切勿一開始就想設計出完美的程序或者速度很快的程序。
- 要以實際測試數據爲基準
1、影響性能的因素
-
上下文的切換
是指CPU 從一個進程或線程切換到另一個進程或線程。一次上下文切換花費5000~10000個時鐘週期,幾微秒。在上下文切換過程中,CPU會停止處理當前運行的程序,並保存當前程序運行的具體位置以便之後繼續運行。從這個角度來看,上下文切換有點像我們同時閱讀幾本書,在來回切換書本的同時我們需要記住每本書當前讀到的頁碼。
上下文切換通常是計算密集型的。也就是說,它需要相當可觀的處理器時間。所以,上下文切換對系統來說意味着消耗大量的 CPU 時間,事實上,可能是操作系統中時間消耗最大的操作。 -
內存同步
一般指加鎖,對加鎖來說,需要增加額外的指令,這些指令都需要刷新緩存等等操作。 -
阻塞
會導致線程掛起【掛起:掛起進程在操作系統中可以定義爲暫時被淘汰出內存的進程,機器的資源是有限的,在資源不足的情況下,操作系統對在內存中的程序進行合理的安排,其中有的進程被暫時調離出內存,當條件允許的時候,會被操作系統再次調回內存,重新進入等待被執行的狀態即就緒態,系統在超過一定的時間沒有任何動作】。很明顯這個操作包括兩次額外的上下文切換
2、避免性能問題
- 減少鎖的競爭
類似於活鎖這樣狀態,避免線程對鎖的過於活躍的競爭且拿不到。 - 減少鎖的粒度
使用鎖的時候,鎖所保護的對象是多個,當這些多個對象其實是獨立變化的時候,不如用多個鎖來一一保護這些對象。但是如果有同時要持有多個鎖的業務方法,要注意避免發生死鎖 - 縮小鎖的範圍
對鎖的持有實現快進快出,儘量縮短持由鎖的的時間。將一些與鎖無關的代碼移出鎖的範圍,特別是一些耗時,可能阻塞的操作 - 鎖分段
類似於concurrentHashMap的Segment操作,可提升併發性能 - 替換獨佔鎖
在業務允許的情況下:
1、使用讀寫鎖,
2、用自旋CAS
3、使用系統的併發容器
二、線程安全的單例模式
這裏介紹我的另一片文章:線程安全的單例模式