java線程同步和線程安全

多個線程訪問共享資源(臨界資源)的時候,會出現線程安全問題,安全問題大多數是可見性和原子性問題。但這樣說可能並不嚴謹,線程的安全性可能更在於他對錯誤性的定義,當多個線程訪問一個類時,如果可以需要考慮運行時環境的調度和交換,並且需要額外的同步保證結果正確,我們認爲這個線程是有線程安全性問題的。下面我們討論一下可見性和原子性帶來的線程安全問題。

可見性的問題

例如執行多個線程執行a++,那麼多個線程就會被分配到不同的處理器上,每個處理器都從主存上覆制操作一份拷貝,處理完成後複製給主存。由於分配到了不同的處理器上,兩個線程的操作可能會互相覆蓋,這樣的結果就會和預想的又偏差。

原子性分解的問題

原子性就是不可分割的操作,在硬件層面上是指不被線程調度器中斷,也就是說一個操作要麼執行完,要麼不執行。上面的例子中a++就不是原子性操作,首先要讀取X的值,然後+1,最後寫入工作內存中。三個步驟任何一部打斷,都會影響最終的結果。但是a=1和return就是原子性操作了。

synchronized關鍵字

爲了解決上述的原子性和可見性帶來的線程安全問題,Java提供了同步機制互斥鎖機制,這個機制保證了在同一時間內只有一個線程能訪問共享資源(臨界資源)。這個機制的保障來源於監視鎖Monitor,在Java中,每個對象都自帶監視鎖,當我們要訪問用synchronized修飾的方法或代碼塊的時候,都意味着進入這個方法或者代碼塊要加鎖,離開要放鎖。而且Synchronizd可以顯示的說明對哪個對象加鎖,如下例子:

[html] view plain copy

  1. synchronized public void add(){  
  2.     a++;  
  3. }  
  4. // 等價於  
  5. public void add(){  
  6.     synchronized(this){  
  7.         a++;  
  8.     }  
  9. }  

對同步機制互斥鎖小結

1、每個對象有自己的監視鎖Monitor,這意味着多個線程訪問一個對象的Synchronizd方法或者代碼塊時,需要等其他線程放鎖纔可訪問。相對的多個對象的監視鎖不存在互斥情況。

2、互斥機制只能保證Synchronizd代碼塊裏的代碼同步,而不再代碼塊裏的代碼不能得到保證。

3、子類重寫父類的Synchronizd方法不能保證同步。因爲Synchronizd並不屬於方法定義的一部分。

4、SYnchronizd修飾靜態方法時,等同於給該類的所有對象都加了一把鎖。因爲靜態方法屬於類,不屬於對象。

5,Synchronizd把類當監視鎖的話,效果等同4.

5、Synchronizd修飾的方法的監視鎖(Monitor)也是重入鎖,也就是說當一個線程獲得監視鎖之後,可以再次獲得該對象的鎖。例如,線程A調用一個對象的同步方法之後,可以調用該對象的另一個同步方法。

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