Synchronized 锁的两种方式分别的针对方法的锁和针对代码块的锁。
代码块锁
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 来看下字节码指令
$ 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
}
我们可以从指令中看到两个指令: monitorenter 和 monitorexit
这两个指令分别表示获得对象锁和释放对象锁
当一个线程在执行monitorenter指令时,会尝试获得对象锁(锁的几种类型),如果获取成功,则执行代码块中的内容,如果获取失败,则等待释放锁。synchronized代码块执行完后,执行monitorexit指令,释放monitor对象锁。
详细描述如下
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.
大概含义是每个对象都有一个对象锁,这个对象锁的enter count是0,就可以让多个线程抢占,如果被某个线程抢占成功,则enter count加1,当执行monitorexit的时候,这个enter count减一,当被减为0时,表明该线程释放锁。
同时,如果一个线程成功获取到monitor,可以多次执行monitorenter,enter count 多次加1,释放时也多次执行monitorexit使得enter count 减为0
网友评论