此文是對《JAVA多線程編程核心技術》的一點總結,如果想要了解具體細節可以去看原書。
第二章 對象及變量的併發訪問
-
synchronized對象監視器爲Object時的使用
a)、synchorized修飾非靜態方法時,synchorinzed獲得的鎖都是對象鎖,而不是把一段代碼或方法當作鎖,哪個線程先執行synchronized方法,哪個線程就持有該方法所屬對象的鎖Lock,那麼其他線程只能呈等待狀態,前提是多個線程訪問的是同一個對象。如果多個線程訪問多個對象,則JVM會創建多個鎖。
b)、A線程先持有object對象的Lock鎖時,B線程可以以異步的方式調用object對象中的非synchronized類型的方法,但是如果調用synchronized類型的方法則需等待A線程釋放object對象的Lock鎖。
c)、當一個線程執行的代碼出現異常時,其所持有的鎖會自動釋放。
d)、同步不具有繼承性
e)、synchronized擁有鎖重入功能,也就是在使用synchronized時,當一個線程得到一個對象鎖後,再次請求改對象鎖時是可以再次得到該對象鎖的,也就是說一個synchronized方法內部可以調用本類其他synchronized方法,這是爲了防止死鎖。將任意對象作爲對象監視器
java支持對“任意對象”作爲“對象監視器”來實現同步的功能。這個“任意對象”大多數是實例變量及方法的參數,使用格式爲synchronized(非this)對象。鎖非this對象具有一定的優勢:如果一個類中有很多個synchronized方法,這時雖然可以同步,但是受到阻塞,影響運行效率。如果使用同步代碼塊鎖非this對象,則synchronized(非this)代碼塊中的程序與同步方法時異步的,不與其他鎖this同步方法爭搶this鎖,大大提高運行效率。synchronized(非this對象)格式的作用只有1種:synchronized(非this對象)同步代碼塊:
在多個線程持有“對象監視器”爲同一個對象的前提下,同一時間只有一個線程可以執行synchronized(非this對象)同步代碼塊中的代碼。
當持有“對象監視器”爲同一個對象的前提下,同一時間只有一個線程可以執行synchronized(非this對象)同步代碼塊中的代碼 -
synchronized對象監視器爲Class時的使用
Class鎖可以對類的所有對象實例起作用。
synchronized關鍵字加到static靜態方法上是給Class類上鎖,而synchronized關鍵字加到非static靜態方法上是給對象上鎖。
-
synchronized鎖重入
關鍵字synchronized擁有鎖重入的功能,也就是在使用synchronized時,當一個線程得到一個對象鎖後,再次請求此對象鎖時是可以再次得到該對象的鎖的。這也證明在一個synchronized方法/塊的內部調用本類的其他synchronized方法/塊時,是永遠可以得到鎖的。
當存在父子類繼承關係時,子類是完全可以通過“可重入鎖”調用父類的同步方法的
-
數據類型String的常量特性
在JVM中具有String常量池緩存的功能,同步synchronized代碼塊中使用String作爲鎖對象時,兩個string鎖對象有可能是同一個鎖對象。在大多數的情況下,同步synchronized代碼塊都不使用String作爲鎖對象,而改用其他,比如new Object()實例化一個Object對象,但它並不放入緩存中,這樣就是兩個不同的鎖對象。
-
關鍵字volatile的主要作用
關鍵字volatile的主要作用是使變量在多個線程間可見。
線程工作時的內存結構如下:
通過使用volatile關鍵字,強制的從公共內存中讀取變量的值。內存結構如下:
-
關鍵字volatile與synchronized的區別及使用情況
1)關鍵字volatile性能比synchronized要好,並且volatile只能修飾變量,而sy可以修飾方法,以及代碼塊。在開發中使用synchronized的比率較大。
2)多線程訪問volatile不會發現阻塞,而synchronized會出現阻塞。
3)volatile能保證數據的可見性,但不能保證原子性;而synchronized可以保證原子性,也可以間接保證可見性。
4)volatile解決的是變量在多個線程之間的可見性,而synchronized解決的是多個線程之間訪問資源的同步性。