標籤:thread java synchronized
Context:
關於Thread老是看了忘,看了忘記。還是寫下來吧。翻譯的是orcale官網的鎖解釋文檔地址
鎖:
同步機制是圍繞內部實體即intrinsic lock(intrinsic固有的、本質的)、monitor lock(監控鎖)。Intrinsic lock在同步上扮演兩個角色:1.強制的排他性讀取對象的狀態(也就是線程訪問對象的屬性、方法等是互斥的)、2保持happens-before relationship來確保變數、方法的可見度。
每個對象都有與其關聯的intrinsic lock。按照慣例,一個線程需要 排他的、一致性(consistent)讀取對象的屬性,必須擷取該對象的鎖。並在處理完後釋放intrinsic lock。線上程擷取和釋放鎖之間,線程被稱為擁有intrinsic lock。只要一個線程持有intrinsic lock,其他的線程嘗試擷取這個鎖時就會被阻塞。
兩種Synchronized:Synchronized方法:
用法: public synchronized void sayHello(){}
a)非靜態方法:intrinsic lock是該調用方法的對象,如b.sayHello 線程持有的intrinsic lock就是對象b的intrinsic lock
b) 靜態方法:例如 public static synchronized void getInstance()。調用是Test.getInstance();這裡沒有對象,線程持有的intrinsic lock是Test對象對應的Class類的對象,也就是假設Test類的對象testObject.getClass()所獲得的對象。而該對象是在類的載入(Loading)階段 在Java堆中產生一個代表改類的java.lang.Class對象,作為方法區的訪問入口。(詳見我以前的部落格點擊開啟連結 )所以他是類層級的鎖。
Synchronized聲明:
用法:
public void addName(String name) { synchronized(this) { lastName = name; nameCount++; } nameList.add(name);} a)不是用該方法的對象來做為intrinsic lock,而是你指定任意一個對象
好處
1:不對整個方法進行同步,而是對一部分進行同步,效率要高些,也更安全(從同步的方法中調用別的對象的方法,可能造成Liveness問(如:死結)。如例子,就沒有吧nameList.add(name);加到裡面。
:
public class MsLunch { private long c1 = 0; private long c2 = 0; private Object lock1 = new Object(); private Object lock2 = new Object(); public void inc1() { synchronized(lock1) { c1++; } } public void inc2() { synchronized(lock2) { c2++; } }} 2.c1的改變和c2的改變沒什麼邏輯上的關聯,可以兩個線程交叉改變。所以就沒有必要用Synchronized Method,否則鎖是該方法對象,兩個inc1、inc2無法被兩個線程同時訪問。
重新進入Synchronized:
雖然a線程無法進入b線程鎖住的方法,但是b線程可以再次進入b線程持有鎖的方法,並對鎖的進入進行累加。這樣就可以遞迴調用了嘛。
Java Thread Synchroize兩種方式的優劣