1、适应性自旋
因为阻塞或者唤醒一个JAVA的线程需要操作系统切换CPU状态来完成,这种状态的转换需要耗费处理器时间。如果同步代码块中的内容过于简单,很可能导致状态转换消耗的时间比用户代码执行的时间还要长。
为了解决这个问题,我们可以让后面请求锁的线程“稍等一下”,执行一个忙循环,进行自旋。此时没有放弃处理器的执行时间。如果自旋超过了限定的次数,仍然没有成功获得锁,那就会使用传统的方式去挂起线程了。
那什么叫做适应性自旋呢?就是在同一个锁对象上,如果自旋等待刚刚成功获得过锁,那虚拟机就会认为这次自旋获得锁的概率挺大,就会允许其自旋等待持续相对更长的时间。相反,如果自旋很少成功获得过锁,则可能省略掉自旋过程。
2、锁消除
指虚拟机即时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。
3、锁粗化
如果一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作是出现在循环体中的,那即使没有线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。
如果虚拟机探测到一串零碎的操作都对同一个对象加锁,将会把加锁同步的范围粗化到整个操作序列的外部,这样只需要加锁一次就够了。
4、轻量级锁
在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能损耗。
适用场景:无实际竞争,多个线程交替使用锁;允许短时间的锁竞争。
5、偏向锁
偏向锁用于减少无竞争且只有一个线程使用锁的情况下,使用轻量级锁产生的性能消耗。轻量级锁每次申请、释放锁都至少需要一次CAS,但偏向锁只有初始化时需要一次CAS。
适用场景:无实际竞争,且将来只有第一个申请锁的线程会使用锁。