1. 程式人生 > >java併發理論簡述

java併發理論簡述

一:為什麼需要多執行緒?

執行緒是Java語言中不可或缺的重要部分,它們能使複雜的非同步程式碼變得簡單,簡化複雜系統的開發;能充分發揮多處理器系統的強大計算能力。多執行緒和多程序的區別與選擇可以參考我的另一篇部落格。

(1) 優點

  1. 充分利用硬體資源。由於執行緒是cpu的基本排程單位,所以如果是單執行緒,那麼最多隻能同時在一個處理器上執行,意味著其他的CPU資源都將被浪費。而多執行緒可以同時在多個處理器上執行,只要各個執行緒間的通訊設計正確,那麼多執行緒將能充分利用處理器的資源。

  2. 結構優雅。多執行緒程式能將程式碼量巨大,複雜的程式分成一個個簡單的功能模組,每塊實現複雜程式的一部分單一功能,這將會使得程式的建模,測試更加方便,結構更加清晰,更加優雅。

  3. 簡化非同步處理。為了避免阻塞,單執行緒應用程式必須使用非阻塞I/O,這樣的I/O複雜性遠遠高於同步I/O,並且容易出錯。

(2) 缺點

  1. 執行緒安全:由於統一程序下的多個執行緒是共享同樣的地址空間和資料的,又由於執行緒執行順序的不可預知性,一個執行緒可能會修改其他執行緒正在使用的變數,這一方面是給資料共享帶來了便利;另一方面,如果處理不當,會產生髒讀,幻讀等問題,好在Java提供了一系列的同步機制來幫助解決這一問題,例如內建鎖。

  2. 活躍性問題。可能會發生長時間的等待鎖,甚至是死鎖。

  3. 效能問題。 執行緒的頻繁排程切換會浪費資源,同步機制會導致記憶體緩衝區的資料無效,以及增加同步流量。

二:執行緒安全

(1) 定義:當多個執行緒訪問某個類時,不管執行時環境採用何種排程方式或者這些執行緒將如何交替執行,並且在主除錯程式碼中不需要任何額外的同步或者協同,這個類都能表現出正確的行為,則稱這個類時執行緒安全的。執行緒安全類中封裝了必要的同步機制,因此客戶端無須進一步採取同步措施。

(2) 執行緒安全產生的原因:正確性取決於多個執行緒的交替執行時序,產生了競態條件。

(3) 原子類: 應儘量使用原子類,這樣會讓你分析執行緒安全時更加方便,但需要注意的是用執行緒安全類構建的類並不能保證執行緒安全。例如,一個AtomicInteger get() 和 AtomicInteger set() 是執行緒安全的,在一個類的一個方法 f()中同時用到了這兩個方法,此時的f()就是執行緒不安全的,因為你不能保證這個複合操作中的get 和 set同時更新。

三:解決機制

  1. 加鎖。

(1) 鎖能使其保護的程式碼以序列的形式來訪問,當給一個複合操作加鎖後,能使其成為原子操作。一種錯誤的思想是隻要對寫資料的方法加鎖,其實這是錯的,對資料進行操作的所有方法都需加鎖,不管是讀還是寫。

(2) 加鎖時需要考慮效能問題,不能總是一味地給整個方法加鎖synchronized就了事了,應該將方法中不影響共享狀態且執行時間比較長的程式碼分離出去。

(3) 加鎖的含義不僅僅侷限於互斥,還包括可見性。為了確保所有執行緒都能看見最新值,讀操作和寫操作必須使用同樣的鎖物件。

  1. 不共享狀態

(1) 無狀態物件: 無狀態物件一定是執行緒安全的,因為不會影響到其他執行緒。

(2) 執行緒關閉: 僅在單執行緒環境下使用。

  1. 不可變物件

可以使用final修飾的物件保證執行緒安全,由於final修飾的引用型變數(除String外)不可變是指引用不可變,但其指向的物件是可變的,所以此類必須安全釋出,也即不能對外提供可以修改final物件的介面。