併發程式設計時,必須考慮安全性問題,即執行緒安全,所謂執行緒安全就是可以同時被多個執行緒呼叫,呼叫者無須額外的操作,程式也不會出現錯誤的結果。
要使程式是執行緒安全的,必須考慮以下2點:
是否存在競態條件,常見的是那些先檢查後執行的操作行為,它的正確結果取決於運氣。避免錯誤結果的方法是保證操作的原子性,通常使用加鎖,也有一些原子變數類可以達到目的。
物件狀態在記憶體中是否可見,即當乙個執行緒修改了物件的狀態後,其他執行緒不一定看到修改後的狀態。保證其他執行緒總是能看到最新狀態的方法有2種:一種是加鎖,另一種是使用volatile變數。
於是得出幾個結論:
加鎖機制可保證可見性和原子性,所以能保證執行緒安全;
原子變數可保證原子性,但不能保證可見性,所以不能保證執行緒安全;
volatile變數能保證可見性,但不能保證原子性,所以不能保證執行緒安全;
volatile的原子變數能保證執行緒安全。
除此之外,還有一些物件一定是執行緒安全的:
無狀態物件;
不可變物件。
但是加鎖機制會產生活躍性問題,活躍性問題關注正確的行為是否一定會發生,主要有死鎖問題。
死鎖簡單來講是這樣的:執行緒a持有鎖l並想獲得鎖m,同時執行緒b持有鎖m並想獲得鎖l,這時執行緒a和b都永久阻塞。
避免死鎖的關鍵是要保證每個執行緒獲取鎖的順序必須相同,如上面執行緒a和b獲取鎖的順序如果都是先獲取鎖l再獲取鎖m,就不會發生死鎖問題。
當持有鎖時呼叫外部方法,會很難分析獲取鎖的順序,要盡量避免。
編碼參考:
將所有可變狀態都封裝在物件內部,並通過物件的內建鎖對所有訪問可變狀態的**進行同步;
擴充套件執行緒安全的容器類時,在新類中委託容器類的其他方法,使用新鎖,不要關心原來的容器類是否執行緒安全。
JAVA併發程式設計的理解
併發程式設計時,必須考慮安全性問題,即執行緒安全,所謂執行緒安全就是可以同時被多個執行緒呼叫,呼叫者無須額外的操作,程式也不會出現錯誤的結果。要使程式是執行緒安全的,必須考慮以下2點 是否存在競態條件,常見的是那些先檢查後執行的操作行為,它的正確結果取決於運氣。避免錯誤結果的方法是保證操作的原子性,...
JAVA併發程式設計
通過常量字串 string 來呼叫 wait 或 notify 方法所導致的問題是,jvm 編譯器會在內部自動將內容相同的 string 轉變為相同的物件。這意味著,即便你建立了兩個不同的 mywaitnotify 例項,他們內部的 mymonitorobject 變數也會指向相同的 string ...
Java併發程式設計
執行緒之間通訊 1.加鎖 object.wait 釋放鎖 object.notify 與sychronized 聯合使用,object lock new object sychronized lock sychronized lock 2.改進 無需加鎖並發包下 countdownlatch.awa...