jdk1.6以后,JVM对 synchronized 锁进行了优化:
锁消除
锁消除是 JIT编译器对 synchronized 锁的优化,在编译的时候,JIT编译器会通过逃逸分析技术,来分析synchronized 锁对象,如果只可能被一个线程加锁,这个时候编译就不用加入monitorenter 和 monitorexit 的指令。
锁粗化
JIT编译器发现代码里多次加锁释放锁,会给合并为一把锁。
偏向锁
monitorenter 和 monitorexit 的指令是要使用CAS操作加锁释放锁,开销比较大, 因此如果发现大概率只有一个线程来竞争这个锁,就会给这个锁维护一个偏好(bias),后面加锁释放锁基于这个bias来执行,不需要通过CAS,但是如果其他线程也来竞争这个锁,那么此时就会收回之前分配的bias偏好。
轻量级锁
如果偏向锁没能成功实现,就是因为多个线程在竞争锁,此时会尝试采用轻量锁的方式,就是将对象头的 Mark Word 里的轻量级指针,尝试指向持有锁的线程,然后判断是不是要自己加锁。如果失败,这个时候就会升级为重量级锁。
适应性锁
如果各个线程持有锁时间很短,那么一个线程竞争锁不到,就会暂停发生上下文切换 ,让其他线程来执行,但是其他线程很快又释放了锁,再来唤醒暂停的线程,这种情况下,线程会频繁的进行上下文切换,导致开销过大,这个时候可以给它上一个自旋锁,来减少上下文切换。