Java 知识 -- 锁

本文最后更新于:3 天前

Java 中的锁

  1. ReentrantLock

    大部分 JDK 级别加锁+CAS(CPU指令,非常快)

    只有在资源竞争,加锁失败的情况下,release CPU,才会阻塞线程

    非公平

  2. synchronize

    • JDK 1.6 以前直接更改操作系统 -> JDK 1.6 以后,首先通过对象头里面存储锁状态标识,升级为重量锁之后才调用操作系统代码

    • 加锁过程:

      1. 在代码进入同步块的时候,如果同步对象锁状态为无锁状态 ( 101)(锁标志位为“01”状态,能否偏向为“1”),虚拟机首先将在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝,官方称之为 Displaced Mark Word。这时候线程堆栈与对象头的状态如图2.1所示。

      2. 拷贝对象头中的Mark Word复制到锁记录中。

      3. 拷贝成功后,虚拟机将使用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指针,并将Lock record里的owner指针指向object mark word。如果更新成功,则执行步骤(4),否则执行步骤(5)。

      4. 如果这个更新动作成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位设置为“00”,即表示此对象处于轻量级锁定状态,这时候线程堆栈与对象头的状态如图2.2所示。

      5. 如果这个更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈帧,如果是就说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块继续执行。否则说明多个线程竞争锁,轻量级锁就要膨胀为重量级锁,锁标志的状态值变为“10”,Mark Word中存储的就是指向重量级锁(互斥量)的指针,后面等待锁的线程也要进入阻塞状态。 而当前线程便尝试使用自旋来获取锁,自旋就是为了不让线程阻塞,而采用循环去获取锁的过程。

    偏向锁会记录当前线程 id

    但是轻量锁不会记录

    • 偏向锁膨胀为轻量锁的条件:

      1. 001 不可能偏向 -> 000 升级为轻量锁

      2. 线程交替运行

    • 锁的膨胀一般是不可逆的

      可逆和epoch有关

    对象锁和类锁是不一样的

    对象在堆上,类信息则在方法区

    所以 new 多个类,多个实例同时访问各自的对象锁就无效

    例如:

    public synchronized (this)

    但是如果是类锁就不是这样的,


对象头

||                       62位                      |锁状态|                                     |                           过程                        |锁状态|
|    无锁可偏向    |          unused:57         | u1 | age:4 |   1   | 01 | klass word (64,如果开启了指针压缩就是32) |                        默认初始状态                     | 101 |
|   无锁不可偏向   |  unused: 25 | hashcode:31  | u1 | age:4 |   0   | 01 |               klass word             |  计算了hashcode,保存了hashcode,但是没有地方存偏向锁的线程id了 | 001 |
| 有偏向锁,已经偏向 | thread(线程id): 54| epoch:2 | u1 | age:4 |   1   | 01 |               klass word             |            默认状态到偏向锁状态,没有计算hashcode           | 101 |
|      轻量锁     |     ptr_to_lock_record(指向栈中锁记录的指针):62     | 00 |               klass word             |          线程交替执行,或者由无锁不可偏向状态升级而来          | 000 |
|      重量锁     | ptr_to_heavyweight_monitor(指向重量锁记录的指针):62 | 10 |               klass word             | 轻量锁抢锁失败,自旋锁自旋一段时间,如果还是抢锁失败则会变成重量锁 | ?10 |