1、synchronized关键字

2、Java对象结构与内置锁

2.1、无锁状态

2.2、偏向锁状态

偏向锁是指一段同步代码 一直被同一个线程所访问 这时锁状态就是偏向锁状态。(意思就是同步代码目前一直只被一个线程访问),那边该当前线程会自动获取锁,降低获取锁的代价。
如果内置锁处于偏向状态,当有一个线程来竞争锁时,先用偏向锁,表示内置锁偏爱这个线程,这个线程要执行该锁关联的同步代码时,不需要再做任何检查和切换。偏向锁在竞争不激烈的情况下效率非常高。
偏向锁

2.3、轻量级锁状态

2.4、重量级锁状态

3、偏向锁的原理与实战

4、轻量级锁的原理与实战

5、重量级锁的原理与实战

6、偏向锁、轻量级锁和重量级锁的对比

总结一下synchronized 的执行过程,大致如下:

  1. 当有线程抢锁(申请锁)时,JVM首先检测内置锁对象Mark Word 中的biased_lock(偏向锁标识)是否为 0,lock (锁状态标志位)是否为01,如果都满足,确认内置锁为无锁状态,申请锁线程将偏向锁标识位设置为 1 ,并 将自己的线程ID通过CAS 设置到MarkWord中, 锁处于偏向锁状态。
  2. 如果不满足无锁条件,判断 biased_lock(偏向锁标识)1,并且lock(锁状态标志位)是否为 01 ,如果都满足,确认内置锁对象为可偏向状态

    第一步这是,当线程抢锁时 JVM 先去检测 内置锁对象Mark word中锁的标志位。可 偏向状态

  3. 在内置锁对象确认为可偏向状态之后, JVM检查Mark Word 中的线程ID是否为抢锁线程ID,如果是,就表示抢锁线程处于偏向锁状态,抢锁线程快速获取锁,开始执行临界区代码。

  4. 如果不是Mark word中的线程ID 并未指向抢锁线程,那就通过CAS操作 竞争锁,如果竞争成功,就将MarkWord 中的线程ID 设置为抢锁线程,并且把偏向标志位设置为 1 ,锁标志位设置为01,然后执行临界区代码,此时内置锁对象处于 偏向锁状态
  5. 如果 CAS 竞争失败,就说明发生了竞争,撤销偏向锁,然后修改锁的状态位 为 00,进而升级为轻量级锁
  6. 升级为轻量级锁之后,JVM 使用CAS 将锁对象的Mark Word 替换为抢锁线程的锁记录指针,如果成功,抢锁线程就获得了锁。如果替换失败,就表明其他线程竞争锁,JVM 尝试使用 CAS 自旋替换抢锁线程的锁记录指针,如果自旋成功(抢锁成功),那么锁对象依然处于轻量级锁状态。
  7. 如果JVM 的CAS 替换锁记录指针自旋失败,轻量级锁膨胀为重量级锁,后面等待锁的线程也要进入阻塞状态。

总体来说,偏向锁是在没有发生锁竞争用的情况下使用的; 一旦有了第二个线程争用锁,偏向锁就会升级为轻量级锁;如果锁争用很激烈,轻量级锁的CAS 自旋达到阈值后,轻量级锁就会升级为重量级锁。三种内置锁的对比如表2-6所示。