我先讲一下锁的概述吧
为了减轻获得锁和释放锁的性能消耗,在JDK1.6时,引入了【偏向锁】和【轻量级锁】。所以锁一共有四种状态,级别从低到高:无锁状态,偏向锁状态,轻量级锁状态,重量级锁状态。线程在竞争过程中锁会进行升级。而且锁一旦升级后无法降级,比如说,偏向锁升级为轻量级后是不能降级为偏向锁的。
接下来介绍一下偏向锁。
首先,为什么要引入偏向锁呢?
因为研究JVM的人发现,在大多数情况下,锁之间并不存在多个线程之间的竞争,反而存在一个线程多次获得锁的现象。所以为了减少加锁和解锁的性能消耗,引入了【偏向锁】。
当一个线程访问同步区并获得锁时,会在对象头和栈帧的锁记录中存储锁偏向的线程的ID。之后线程再进入和退出同步块时,就【不需要进行CAS操作来加锁和解锁了,只需要测试对象头的Markword中是否存储着指向该线程的偏向锁】。如果测试通过,则表示获得锁。如果不通过,那么线程会去先检查对象头的Markword的偏向锁标志位是否为1,即检查该对象是否为偏向锁。如果不是,则通过CAS来竞争该锁;如果是,就尝试使用CAS操作让对象头中的偏向锁指向当前线程。
我接下来再介绍一下偏向锁的撤销过程。
偏向锁采用了一种【等到竞争现象出现时才释放锁】的机制,也就是说当有其他线程尝试获取该偏向锁时,持有该偏向锁的线程才会释放锁。偏向锁的撤销需要等待全局安全点(没有字节码执行的时候)。它会首先暂停持有偏向锁的线程,然后检查该线程是否在活动状态。如果该线程不在活动状态,那么就会将对象头重置为无锁状态。如果线程在活动状态,就会升级为轻量级锁,并进行CAS竞争锁操作。