- synchronized是JVM的语法糖,主要是通过JVM来控制的。其实现原理依赖于JVM的监视器和对象头。
- synchronized修饰方法时,JVM会通过编译完的字节码的访问标记来区分该方法是否被synchronized修饰,在进入方法的时候就会进行获得锁的竞争,获得锁后才能执行方法体
- synchronized在修饰代码块时,编译后的字节码就会在代码块的前后加上monitorenter和monitorexit标记,一样在进入代码块之前,要先获得锁
- 对象头信息里有一个markword,是实现synchronized的关键,会根据锁的不同状态保存不同的信息。
- 无锁:保存hashcode
- 偏向锁:保存线程ID和偏向标记
- 轻量级锁:保存指向栈中锁记录的指针
- 重量级锁,报错指向monitor的指针
- 加锁流程:
- 服务起来之后,4s以内只能获得无锁,超过4s才能获得匿名偏向锁(markword中未指定线程id)
- 为什么要延迟4s?
- 因为jvm内部代码也用到了很多synchronized,如果启动直接开启偏向锁,如果产生竞争,就会导致锁的升级到轻量级锁,锁的升级会带来额外的性能的消耗
- 为什么要延迟4s?
- 偏向锁解锁完成后,对象头中的线程id不会清0,如果当前线程在进行加锁就不用赋值线程id了
- 如果偏向锁解锁后,另外一个线程对同一个资源(object)加锁,就会升级成轻量级锁
- 轻量级锁解锁后就会变成无锁对象(注意这里不会回到偏向锁(一次性的))
- 无锁对象再加锁,就会变成轻量级锁
- 初始化成可偏向状态后,该对象调用hashCode()后,会变成无锁对象
- 偏向锁持有锁的条件下,该锁对象调用hashCode()后,会变成重量级锁
- 服务起来之后,4s以内只能获得无锁,超过4s才能获得匿名偏向锁(markword中未指定线程id)