synchronized 关键字底层原理属于 JVM 层⾯。
1. synchronized 同步语句块的情况
public class SynchronizedDemo {
public void method() {
synchronized(this) {
System.out.println("synchronized 代码块");
}
}
}
通过 JDK ⾃带的javap
命令查看SynchronizedDemo
类的相关字节码信息:⾸先切换到类的对应⽬录执⾏javac SynchronizedDemo.java
命令⽣成编译后的.class
⽂件,然后执⾏javap -c -s -v -l SynchronizedDemo.class
。
从上⾯我们可以看出:
synchronized
同步语句块的实现使⽤的是monitorenter
和monitorexit
指令,其中monitorenter
指令指向同步代码块的开始位置,monitorexit
指令则指明同步代码块的结束位置。
当执⾏monitorenter
指令时,线程试图获取锁也就是获取对象监视器monitor
的持有权。
在 Java 虚拟机(HotSpot)中,Monitor 是基于 C++ 实现的,由ObjectMonitor实现的。每个对象中都内置了⼀个 ObjectMonitor 对象。
另外,wait/notify
等⽅法也依赖于monitor
对象,这就是为什么只有在同步的块或者⽅法中才能调⽤wait/notify
等⽅法,否则会抛出java.lang.IllegalMonitorStateException
的异常的原因。
在执⾏monitorenter
时,会尝试获取对象的锁,如果锁的计数器为 0 则表示锁可以被获取,获取后将锁计数器设为 1 也就是加 1。
在执⾏monitorexit
指令后,将锁计数器设为 0,表明锁被释放。如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外⼀个线程释放为⽌。
2. synchronized 修饰⽅法的的情况
public class SynchronizedDemo2 {
public synchronized void method() {
System.out.println("synchronized ⽅法");
}
}
synchronized
修饰的⽅法并没有monitorenter
指令和monitorexit
指令,取得代之的确实是ACC_SYNCHRONIZED
标识,该标识指明了该⽅法是⼀个同步⽅法。JVM 通过该ACC_SYNCHRONIZED
访问标志来辨别⼀个⽅法是否声明为同步⽅法,从⽽执⾏相应的同步调⽤。
3. 总结
synchronized
同步语句块的实现使⽤的是monitorenter
和monitorexit
指令,其中monitorenter
指令指向同步代码块的开始位置,monitorexit
指令则指明同步代码块的结束位置。
synchronized
修饰的⽅法并没有monitorenter
指令和monitorexit
指令,取得代之的确实是ACC_SYNCHRONIZED
标识,该标识指明了该⽅法是⼀个同步⽅法。
不过两者的本质都是对对象监视器·monitor·的获取。
留言