synchronized关键字的底层原理
synchronized 关键字底层原理属于 JVM 层⾯。
同步代码块
1 | public class SynchronizedDemo { |
使用java -v -p
查看字节码文件
从上⾯我们可以看出:
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,表明锁被释放。如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外⼀个线程释放为⽌。
至于为啥会有两个monitorexit
指令。是因为防止同步代码块存在异常,无法正常释放资源。相当于try-catch-finally
在finally中释放资源。这也就解释了为啥synchronized为啥能自动释放资源,也就是底层帮你实现了相关步骤。
同步方法
1 | public class SynchronizedDemo { |
同意查看字节码命令。
synchronized 修饰的⽅法并没有 monitorenter 指令和 monitorexit 指令,取得代之的确实是ACC_SYNCHRONIZED
标识,该标识指明了该⽅法是⼀个同步⽅法。JVM 通过该ACC_SYNCHRONIZED
访问标志来辨别⼀个⽅法是否声明为同步⽅法,从⽽执⾏相应的同步调⽤。
总结
- synchronized 同步语句块的实现使⽤的是 monitorenter 和 monitorexit 指令
- 其中 monitorenter 指令指向同步代码块的开始位置, monitorexit 指令则指明同步代码块的结束位 置。
- synchronized 修饰的⽅法并没有 monitorenter 指令和 monitorexit 指令,取得代之的确实是
ACC_SYNCHRONIZED
标识,该标识指明了该⽅法是⼀个同步⽅法。 不过两者的本质都是对对象监视器monitor
的获取。
参考JavaGuide哥面试突击版。