第二章 對象及變量的併發訪問

1.Synchronized關鍵字

a.synchronized加在方法的前部

 public synchronized void synMethod() {

  //方法體

 }

調用用關鍵字synchronized聲明的方法是排隊運行的。但假如線程A持有某對象的鎖,那線程B異步調用非synchronized類型的方法不受限制。

b. synchronized同步代碼塊

synchronized(this)

c.將任意對象作爲監視器

synchronized(非this對象)

 

d.靜態同步

(1)synchronize(class)

 

(2)在靜態方法前面加上synchronized關鍵字

 

小結:

a.synchronized取得的鎖都是對象鎖,而不是把一段代碼或方法當作鎖,在線程的執行過程當中,哪個線程先執行了帶synchronized關鍵字的方法,哪個線程就持有該方法所屬對象的鎖,那麼其他線程只能等待,前提是多個線程訪問的是同一個對象的synchronized方法。如果多個線程訪問多個對象,則JVM會創建多個鎖。

b.如果一個線程已經持有了一個對象的鎖,另外一個線程則不能訪問該對象的同步方法,但是可以訪問該對象的非同步方法。

c.同步不具有繼承性,如果父類的某個方法擁有synchronized關鍵字,子類的該方法若想同步必須手動的加入synchronized關鍵字;

d.關鍵字加到static方法上是給Class上鎖,加到非static是給對象上鎖。

class鎖可以對類的所有實例起作用,即就是在任何時候,只能有一個線程訪問該類的static方法。因爲static方法就是類方法。

Class鎖 鎖住以後,以實例對象爲參數的線程可以獲取到實例對象中的方法。比如User.Class鎖住後,以user1 user2 user3 爲參數的線程還是能獲取到相應對象的鎖。可以理解爲鎖對象是按照地址來判斷鎖住的是不是同一個對象。

線程的私有堆棧


2. volatile關鍵字

主要作用是使變量在多個線程間可見。加volatile關鍵字可強制性從公共堆棧進行取值,而不是從線程私有數據棧中取得變量的值。

小陷阱

將JVM設置爲-server模式,爲了線程運行的效率,會在線程的私有堆棧中取值,在不使用volatile關鍵字的時候,如果對共有堆棧中的值進行改變,會造成值的不統一。

讀取公共內存圖

Atomic相關類

一個原子類型就是一個原子操作可用的類型,可在沒有鎖的情況下做到線程安全。但原子類也不是完全安全,雖然原子操作是安全的,可方法間的調用卻不是原子的,需要用同步。

synchronized和volatile比較

1)關鍵字volatile是線程同步的輕量級實現,性能比synchronized好,且volatile只能修飾變量,synchronized可修飾方法和代碼塊。

2)多線程訪問volatile不會發生阻塞,synchronized會出現阻塞

3)volatile能保證數據可見性,不保證原子性;synchronized可以保證原子性,也可以間接保證可見性,因爲synchronized會將私有內存和公共內存中的數據做同步

4)volatile解決的是變量在多個線程間的可見性,synchronized解決的是多個線程訪問資源的同步性。

volatile不具備同步性,也不具備原子性

如圖:


read and load 從主存複製變量到當前工作內存
use and assign  執行代碼,改變共享變量值 
store and write 用工作內存數據刷新主存相關內容

其中use and assign 可以多次出現

但是這一些操作並不是原子性,也就是 在readload之後,如果主內存count變量發生修改之後,線程工作內存中的值由於已經加載,不會產生對應的變化,所以計算出來的結果會和預期不一樣

對於volatile修飾的變量,jvm虛擬機只是保證從主內存加載到線程工作內存的值是最新的

例如假如線程1,線程2 在進行read,load 操作中,發現主內存中count的值都是5,那麼都會加載這個最新的值

在線程1堆count進行修改之後,會write到主內存中,主內存中的count變量就會變爲6

線程2由於已經進行read,load操作,在進行運算之後,也會更新主內存count的變量值爲6

導致兩個線程及時用volatile關鍵字修改之後,還是會存在併發的情況。

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