synchronized代码块的底层实现

synchronized代码块的底层实现

MDove:咱们先写一个简单的demo,然后看一下它们的字节码:

synchronized代码块的底层实现

 

synchronized代码块的底层实现

MDove:根据虚拟机规范要求,在执行monitorenter指令时,首先要尝试获取对象锁,也就是上文我们提到了monitor对象。如果这个对象没有被锁定,或者当前线程已经拥有了这个对象的锁,那么就把锁的计数器(_count)加1。当然与之对应执行monitorexit指令时,锁的计数器(_count)也会减1。

MDove:如果当前线程获取锁失败,那么就会被阻塞住,进入_WaitSet 中,等待锁被释放为止。

小A:等等,我看到字节码中,有俩个monitorexit指令,这是为什么呢?

MDove:是这样的,编译器需要确保方法中调用过的每条monitorenter指令都要执行对应的monitorexit 指令。为了保证在方法异常时,monitorenter和monitorexit指令也能正常配对执行,编译器会自动产生一个异常处理器,它的目的就是用来执行 异常的monitorexit指令。而字节码中多出的monitorexit指令,就是异常结束时,被执行用来释放monitor的。

小A:我们刚才看的是同步代码块的原理,那么直接修饰在方法上呢?也是通过这个俩个指令吗?

MDove:你别说,还真不是:

synchronized代码块的底层实现

 

synchronized代码块的底层实现

MDove:可以看到:字节码中并没有monitorenter指令和monitorexit指令,取得代之的是ACC_SYNCHRONIZED标识,JVM通过ACC_SYNCHRONIZED标识,就可以知道这是一个需要同步的方法,进而执行上述同步的过程,也就是_count加1,这些过程。

小A:哦,原来是这样。一个是用了指令,一个是用的标识呀~对了,我听说synchronized的性能特别低是这样么?

MDove:这句话不全对,JDK1.5后对synchronized进行了大刀阔斧的优化,这其中涉及到偏向锁、轻量级锁、自旋锁、锁消除等手段。时候也不早了,这些内容今天就不展开了。有机会我们下次再学习吧~