Synchronized 鎖的兩種方式分別的針對(duì)方法的鎖和針對(duì)代碼塊的鎖。
代碼塊鎖
public class A {
public void method() {
synchronized (A.class) {
System.out.println("lock method");
}
System.out.println("unlock method");
}
public static void main(String[] args) {
new A().method();
}
}
首先,我們用javap -c 來(lái)看下字節(jié)碼指令
$ javap -c A
Compiled from "A.java"
public class A {
public A();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void method();
Code:
0: ldc #2 // class A
2: dup
3: astore_1
4: monitorenter
5: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
8: ldc #4 // String lock method
10: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
13: aload_1
14: monitorexit
15: goto 23
18: astore_2
19: aload_1
20: monitorexit
21: aload_2
22: athrow
23: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
26: ldc #6 // String unlock method
28: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
31: return
Exception table:
from to target type
5 15 18 any
18 21 18 any
public static void main(java.lang.String[]);
Code:
0: new #2 // class A
3: dup
4: invokespecial #7 // Method "<init>":()V
7: invokevirtual #8 // Method method:()V
10: return
}
我們可以從指令中看到兩個(gè)指令: monitorenter 和 monitorexit
這兩個(gè)指令分別表示獲得對(duì)象鎖和釋放對(duì)象鎖
當(dāng)一個(gè)線程在執(zhí)行monitorenter指令時(shí),會(huì)嘗試獲得對(duì)象鎖(鎖的幾種類(lèi)型),如果獲取成功,則執(zhí)行代碼塊中的內(nèi)容,如果獲取失敗,則等待釋放鎖。synchronized代碼塊執(zhí)行完后,執(zhí)行monitorexit指令,釋放monitor對(duì)象鎖。
詳細(xì)描述如下
monitorenter:
Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as follows:
? If the entry count of the monitor associated with objectref is zero, the thread enters the monitor and sets its entry count to one. The thread is then the owner of the monitor.
? If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count.
? If another thread already owns the monitor associated with objectref, the thread blocks until the monitor's entry count is zero, then tries again to gain ownership.
monitorexit:
The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.
The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.
大概含義是每個(gè)對(duì)象都有一個(gè)對(duì)象鎖,這個(gè)對(duì)象鎖的enter count是0,就可以讓多個(gè)線程搶占,如果被某個(gè)線程搶占成功,則enter count加1,當(dāng)執(zhí)行monitorexit的時(shí)候,這個(gè)enter count減一,當(dāng)被減為0時(shí),表明該線程釋放鎖。
同時(shí),如果一個(gè)線程成功獲取到monitor,可以多次執(zhí)行monitorenter,enter count 多次加1,釋放時(shí)也多次執(zhí)行monitorexit使得enter count 減為0