0%

java | synchronized 优化 轻量级锁

轻量级锁。

如果一个对象虽然又多线程访问,但是,多线程访问时间是错开的,也就是没有竞争,那么,可以用轻量级锁来优化。

轻量级锁对使用者是透明的。这句话的意思是,synchronized 是一种自适应语法,默认开始是轻量级锁,只有出现同一时间竞争才会改成重量级锁。

1
2
3
4
5
6
7
8
9
10
11
12
static final Object obj = new Object();
public static void method1() {
synchronized( obj ) {
// 同步块 A
method2();
}
}
public static void method2() {
synchronized( obj ) {
// 同步块 B
}
}

A

创建锁记录(Lock Record)对象,每个线程的栈帧都会包含一个锁记录的结构,存储锁定对象的 Mark Word

B

让锁记录中 Object reference 指向锁住的对象,并尝试用 CAS 「CAS是现代CPU广泛支持的一种对内存中的共享数据进行操作的一种特殊指令」 替换 ObjectMark Word,将 Mark Word 的值存入锁记录

对应代码中的 method1 中的 synchronized( obj )

C

如果 CAS 替换成功,对象头中存储了锁记录地址和状态 00(轻量级锁) ,表示由该线程给对象加锁,Lock Record 变为 01

如果 CAS 失败,有两种情况:

  • 如果是其它线程已经持有了该 Object 的轻量级锁,这时表明有竞争,进入锁膨胀过程
  • 如果是线程自己执行了 synchronized 锁重入,就添加一条 Lock Record 作为重入的计数
    • 对应 method2 中的 synchronized( obj )

D

对应 method2 中的 synchronized( obj ) ,对应上述 C 后面的情况

E

当退出 synchronized 代码块(解锁时)

对应于 method2 执行完毕。

如果有取值为 null 的锁记录,表示有重入,这时重置锁记录,表示重入计数减 1

如果锁记录的值不为 null,这时使用 CASMark Word 的值恢复给对象头

  • 成功,则解锁成功
  • 失败,说明轻量级锁进行了锁膨胀或已经升级为重量级锁,进入重量级锁解锁流程

注意:

在轻量级锁的机制下,即便是只有一个线程操作同步区,每次重入一然后执行 CAS 操作。

为了降低这种重入损耗,引进了

请我喝杯咖啡吧~