jdk1.6之后对锁的实现引入了大量的优化,如偏向锁、轻量级锁、自旋锁、自适应自旋锁、锁清除,锁粗化。
- 偏向锁。偏向锁会“偏向”第一个获取到它的线程。在接下来的执行中,如果该锁没有被其他线程获取,则该拥有该锁的线程会直接不进行同步操作。但对于资源竞争比较激烈的场景,偏向锁就会失效,偏向锁失效后会升级为轻量级锁。
- 轻量级锁。 轻量级锁的本意是,在没有多线程竞争的情况下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗,轻量级锁不足要申请互斥量,同步操作使用的是CAS。但是,在多线程竞争激烈的情况下,轻量级锁的性能比重量级锁的性能还有差,所以此时会膨胀为重量级锁。
- 自旋锁。自旋锁是在轻量级锁失效后,防止线程真的在操作系统层面挂起,而做的一种优化的手段。使用自旋锁后,在发生多线程竞争时,线程不会被立即挂起,而是会做“自旋”的操作,重复发起请求。因为挂起/恢复线程的操作都要转到内核态去完成。jdk1.6之前,自旋次数是固定的,若线程请求超过固定次数后还没有获得锁,则该线程会被挂起。在jdk1.6之后,引入了自适应的自旋锁,自旋时间不是固定的,自旋时间由上一次同一个锁上的自旋时间和锁拥有者的状态来决定。
- 锁消除。值得是虚拟机如果检测到共享数据不可能存在竞争,就会进行锁消除,减少毫无意义的竞争锁的时间。
- 锁粗化。即同步的范围尽量小,在共享数据的实际作用域进行同步。