一、線程安全與非線程安全
線程安全: 獲得的執行個體變量的值是經過同步處理的,不會出現髒讀的現象。
非線程安全: 多個線程同時對同一個對象中的同一個執行個體變量進行操作時會出現值被更改,值不同步的情況(也就是“髒讀”),進而影響程式的執行流程。
“非線程安全”的問題存在于“執行個體變量”中,如果是方法内部的私有變量,則不存在“非線程安全”的問題。
二、synchronized 同步方法
格式:synchronized 修飾符 類型 方法名(){}
1.多個對象多個鎖
關鍵字synchronized取得的鎖是對象鎖,而不是把一段代碼或方法當作鎖,這就說明了:如果多個線程通路同一個類的不同的執行個體的相同名稱的同步方法,代碼是以異步的方式運作的,因為JVM建立了多個鎖。
2.鎖重入
當一個線程得到一個對象鎖後,再次請求此對象鎖時是可以得到該對象的鎖的。這也證明在一個synchronized 方法/塊的内部調用本類的其他的synchronized 方法/塊時,是永遠可以得到鎖的。
3.出現異常,鎖自動釋放
當一個線程執行的代碼出現異常時,其所持有的鎖會自動釋放。這樣可以避免出現死鎖。
4.同步不具有繼承性
子類重寫父類中的同步方法時,synchronized的作用不會被繼承。運作是以異步方式運作的。如果想要同步運作,需要在重寫後的方法前邊加 synchronized。
三、synchronized 同步語句塊
使用synchronized 聲明方法在某些情況下是有弊端的,比如A線程調用同步方法執行一個長時間的任務,那麼B線程則必須等待比較長的時間。這時如果使用synchronized 同步語句塊可以很好地解決這一問題。
1.一半同步,一半異步
在synchronized塊中的代碼是同步執行,不在synchronized塊中的就是異步執行的。
2.synchronized 代碼塊間的同步性
在使用synchronized(this)代碼塊時要注意:當一個線程通路對象的一個synchronized(this)同步代碼塊時,其他線程對同一個對象中的所有其他synchronized(this)同步代碼塊的通路将被阻塞。
3.synchronized(this) 代碼塊鎖定
synchronized(this) 代碼塊鎖定的是目前對象。
4.synchronized() 代碼塊将任意對象作為對象螢幕
多個線程調用同一個對象的不同名稱的synchronized 同步方法或synchronized(this)同步代碼塊時,調用的效果是按順序執行,也就是同步的,阻塞的。
Java 還支援對“任意對象”作為“對象螢幕”來實作同步的功能。這個“任意對象”大多是執行個體變量及方法的參數,使用格式為synchronized(非this對象)。
作用:
在多個線程持有“對象螢幕”(非this對象)為同一個對象的前提下,同一時間隻有一個線程可以執行synchronized(非 this對象)同步代碼塊中的代碼。
優點:
如果在一個類中有很多個synchronized方法,這時雖然能實作同步,但會阻塞,會影響運作效率;但如果使用同步代碼塊鎖非this對象,則synchronized(非this)代碼塊中的程式與同步方法是異步的,不與其他鎖this同步方法争搶this鎖,可以大大提高運作效率。
synchronized(非this 對象x) 是将x對象本身作為“對象螢幕”,是以:
1)當多個線程同時執行synchronized(x){}同步代碼塊時呈同步效果。
2)當其它線程執行x對象中的synchronized同步方法(同一個類中的其他同步方法)時呈同步效果。
3)當其他線程執行x對象方法裡面的synchronized(this)代碼塊時 呈同步效果。
四、靜态同步synchronized方法 與 synchronized(class) 同步
關鍵字synchronized 應用在static靜态方法上,作用是:對目前的*.java檔案對應的Class 類進行持鎖。這個鎖和對象鎖不是同一個鎖,Class鎖可以對類的所有對象執行個體起作用。
同步synchronized(class)代碼塊的作用其實和 synchronized static 方法的作用一樣
五、注意 synchronized(String 對象)
在JVM中具有String 常量池緩存的功能,下邊代碼運作結果為 true。
public class Demo{
public static void main(String[] args){
String a = "a";
String b = "a";
System.out.println(a == b);
}
}
将synchronized(string)同步塊與String聯合使用時,要注意常量池帶來的例外。可以使用 new Object() 執行個體化一個Object對象,但它并不放入緩存中。