先上一段代码,如下:
List-1
public class Example2_synchronizer {
@Test
public void test1(){
synchronized (this){
int i=10;
int j=i+1245;
}
}
}
之后用在命令行输入javap -v -p Example2_synchronizer,得到如下片段:
List-2 javap的结果
3: monitorenter
4: bipush 10
6: istore_2
7: iload_2
8: sipush 1245
11: iadd
12: istore_3
13: aload_1
14: monitorexit
15: goto 25
18: astore 4
20: aload_1
21: monitorexit
22: aload 4
24: athrow
25: return
这就是平时说的monitorenter、monitorexit,值得注意的是,有俩个monitorexit。为什么会有俩个monitorexit,因为:如果synchronized块里面的代码抛出异常,那么会执行18、20、21、22、24编号处的指令,它是在释放之前获取的锁。所以Java中synchronized中即使抛出异常,JVM也会释放锁,让其它线程获取该锁。有点像我们操作文件时try{}catch{}finally{关闭文件流}。
来看下JVM 规范里面给出的例子:
图1 Java7的JVM规范中给出的例子
synchronized的实现时在JVM代码中的,synchronized是通过对象的monitorenter/monitorexit来实现的,JVM中有三种不同的monitor实现,也就是我们说的偏向锁、轻量级锁、重量级锁。为什么要引入这么多实现,是为了该善性能。Java利用CAS(compare and swap),在对象头部的mark word处设置线程ID,表示该对象被被线程占有。
锁的升级、降级,就是JVM优化synchronized运行的机制。锁的升级是指从偏向锁升级到轻量级锁,从轻量级锁升级到重量级锁,如何做到的呢?待后面分析
锁共有4种状态,级别从低到高依次为:无状态锁,偏向锁,轻量级锁和重量级锁状态,由于是4种状态,所以用JVM中用2bits可以表示锁的状态。
这篇博客也讲的比较深入:https://blog.csdn.net/u010723709/article/details/50341631
(adsbygoogle = window.adsbygoogle || []).push({});