synchronized的作用是實作線程間同步,它的工作是對同步代碼塊加鎖,使得每一次隻能有一個線程進入同步塊,進而保證線程間安全性。
synchronized有三種用法:
- 指定加鎖對象:對給定的對象加鎖,進入同步代碼塊前要獲得給定對象的鎖。
- 直接作用于執行個體方法:相當于對目前執行個體加鎖,進入同步代碼塊前要獲得目前執行個體的鎖。
- 直接作用于靜态方法:相當于對目前類加鎖,進入同步代碼塊前要獲得目前類的鎖
JVM基于進入和退出Monitor對象來實作方法同步和代碼塊同步。
monitorenter指令是在編譯後插入到同步代碼塊的開始位置,而monitorexit是插入到方法結束處和異常處,JVM要保證每個monitorenter必須有對應的monitorexit與之配對。任何對象都有一個monitor與之關聯,當且一個monitor被持有後,它将處于鎖定狀态。線程執行到monitorenter指令時,将會嘗試擷取對象所對應的monitor的所有權,即嘗試獲得對象的鎖。
synchronized用的鎖是存在Java對象頭裡的。
public class Synchronized {
public static void main(String[] args) {
// 對Synchronized Class對象進行加鎖
synchronized (Synchronized.class) {
}
// 靜态同步方法,對Synchronized Class對象進行加鎖
m();
}
public static synchronized void m() {
}
}
在Synchronized.class同級目錄執行javap–v Synchronized.class部分相關輸出
public static void main(java.lang.String[]);
// 方法修飾符,表示:public staticflags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: ldc #1 // class com/murdock/books/multithread/book/Synchronized
2: dup
3: monitorenter // monitorenter:螢幕進入,擷取鎖
4: monitorexit // monitorexit:螢幕退出,釋放鎖
5: invokestatic #16 // Method m:()V
8: return
public static synchronized void m();
// 方法修飾符,表示: public static synchronized
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
Code:
stack=0, locals=0