先依然描述这三个锁是什么: 这里直接从《深刻理解java虚拟机》粘贴过来。java
Hotspot 的做者通过以往的研究发现大多数状况下锁不只不存在多线程竞争,并且老是由同一线程屡次得到,为了让线程得到锁的代价更低而引入了偏向锁。当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程 ID,之后该线程在进入和退出同步块时不须要花费CAS操做来加锁和解锁,而只需简单的测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁,若是测试成功,表示线程已经得到了锁,若是测试失败,则须要再测试下 Mark Word中偏向锁的标识是否设置成 1(表示当前是偏向锁),若是没有设置,则使用 CAS 竞争锁,若是设置了,则尝试使用 CAS 将对象头的偏向锁指向当前线程。
偏向锁的撤销:偏向锁使用了一种等到竞争出现才释放锁的机制,因此当其余线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁。偏向锁的撤销,须要等待全局安全点(在这个时间点上没有字节码正在执行),它会首先暂停拥有偏向锁的线程,而后检查持有偏向锁的线程是否活着,若是线程不处于活动状态,则将对象头设置成无锁状态,若是线程仍然活着,拥有偏向锁的栈会被执行,遍历偏向对象的锁记录,栈中的锁记录和对象头的Mark Word要么从新偏向于其余线程,要么恢复到无锁或者标记对象不适合做为偏向锁,最后唤醒暂停的线程。安全
轻量级锁加锁:线程在执行同步块以前, JVM会先在当前线程的栈桢中建立用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。而后线程尝试使用 CAS 将对象头中的Mark Word替换为指向锁记录的指针。若是成功,当前线程得到锁,若是失败,表示其余线程竞争锁,当前线程便尝试使用自旋来获取锁。若是有两条以上的线程争用同一个锁,那轻量级锁就再也不有效,要膨胀为量级锁,锁标志的状态值变为”10”,Mark Word中存储的就是指向重量级(互斥量)的指针。多线程
轻量级锁解锁:轻量级解锁时,会使用原子的 CAS 操做来将Displaced Mark Word替换回到对象头,若是成功,则表示没有竞争发生。若是失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。测试
偏向所锁,轻量级锁都是乐观锁,重量级锁是悲观锁。线程
一个对象刚开始实例化的时候,没有任何线程来访问它的时候。它是可偏向的,意味着,它如今认为只可能有一个线程来访问它,因此当第一个线程来访问它的时候,它会偏向这个线程,此时,对象持有偏向锁。偏向第一个线程,这个线程在修改对象头成为偏向锁的时候使用CAS操做,并将对象头中的ThreadID改为本身的ID,以后再次访问这个对象时,只须要对比ID,不须要再使用CAS在进行操做。一旦有第二个线程访问这个对象,由于偏向锁不会主动释放,因此第二个线程能够看到对象时偏向状态,这时代表在这个对象上已经存在竞争了,检查原来持有该对象锁的线程是否依然存活,若是挂了,则能够将对象变为无锁状态,而后从新偏向新的线程,若是原来的线程依然存活,则立刻执行那个线程的操做栈,检查该对象的使用状况,若是仍然须要持有偏向锁,则偏向锁升级为轻量级锁,(偏向锁就是这个时候升级为轻量级锁的)。若是不存在使用了,则能够将对象回复成无锁状态,而后从新偏向。指针
轻量级锁认为竞争存在,可是竞争的程度很轻,通常两个线程对于同一个锁的操做都会错开,或者说稍微等待一下(自旋),另外一个线程就会释放锁。 可是当自旋超过必定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁膨胀为重量级锁,重量级锁使除了拥有锁的线程之外的线程都阻塞,防止CPU空转。对象