JOL 12 BiasedLocking


本篇文章基于V0.16 JOLSample_12_BiasedLocking

这个例子我们深入了解一下 mark word 里存锁的信息。我们可以通过请求锁,释放锁这个过程清楚地看到mark word内容的变化.

在这个例子中,我们演示一下偏向锁定(biased locking). 在Java中每个对象都有可能是同步的目标。 大多数时间,对象都被一个线程锁定过。
在这种情形下,我们可以把对象偏向(biased)到某个线程,然后非常方便地实现同步(synchronization)语义。

为了演示这种情形,我们在before/during/after这三个锁定请求阶段分别打印一下对象的内部数据。你可以看到mark wordbiasablebiased的变化。释放锁之后mark word的状态仍然没有变化,现在这个对象就偏向到之前锁定过的那个线程了。

在JDK9以前,偏向锁定(biased locking)只有当VM启动5秒钟之后才会被启用。因此下面的例子如果在JDK8运行,最好加上-XX:BiasedLockingStartupDelay=0参数.
JDK15以后,偏向锁定(biased locking)默认就不开启了,入股是在JDK15上运行这个例子需要添加参数-XX:+UseBiasedLocking

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class JOLSample_12_BiasedLocking {

public static void main(String[] args) {
out.println(VM.current().details());

final A a = new A();

ClassLayout layout = ClassLayout.parseInstance(a);

out.println("**** Fresh object");
out.println(layout.toPrintable());

synchronized (a) {
out.println("**** With the lock");
out.println(layout.toPrintable());
}

out.println("**** After the lock");
out.println(layout.toPrintable());
}

public static class A {
// no fields
}

}

运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# WARNING | Compressed references base/shifts are guessed by the experiment!
# WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
# Objects are 8 bytes aligned.
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

**** Fresh object
examples.JOLSample_12_ThinLocking$A object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000005 (biasable; age: 0)
8 4 (object header: class) 0xf80121fa
12 4 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

**** With the lock
examples.JOLSample_12_ThinLocking$A object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x00007f85e6809005 (biased: 0x0000001fe179a024; epoch: 0; age: 0)
8 4 (object header: class) 0xf80121fa
12 4 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

**** After the lock
examples.JOLSample_12_ThinLocking$A object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x00007f85e6809005 (biased: 0x0000001fe179a024; epoch: 0; age: 0)
8 4 (object header: class) 0xf80121fa
12 4 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

在我的测试中我使用了amazon-corretto-8.jdk, 发现 -XX:BiasedLockingStartupDelay=0 这个参数加不加或者设置成多少都不会影响偏向锁定, 程序输出结果始终都是如上例一样,锁释放之后还是被锁定的。但是如果使用了-XX:-UseBiasedLocking这个参数,关闭偏向锁定, 锁释放后,mark word值就恢复成了默认值.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
**** Fresh object
org.openjdk.jol.samples.JOLSample_12_BiasedLocking$A object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf80121e5
12 4 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

**** With the lock
org.openjdk.jol.samples.JOLSample_12_BiasedLocking$A object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x000070000fa029e8 (thin lock: 0x000070000fa029e8)
8 4 (object header: class) 0xf80121e5
12 4 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

**** After the lock
org.openjdk.jol.samples.JOLSample_12_BiasedLocking$A object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 4 (object header: class) 0xf80121e5
12 4 (object alignment gap)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

我用-XX:+PrintFlagsFinal参数打印了虚拟机参数

1
2
3
4
5
6
intx BiasedLockingBulkRebiasThreshold          = 20                                  {product}
intx BiasedLockingBulkRevokeThreshold = 40 {product}
intx BiasedLockingDecayTime = 25000 {product}
intx BiasedLockingStartupDelay = 4000 {product}
bool TraceBiasedLocking = false {product}
bool UseBiasedLocking = true {product}

我发现BiasedLockingStartupDelay时间为4秒, 这不应该会生成偏向锁定呀。于是我在代码关键节点加了一下时间,发现是VM.current().details() 这个代码太耗时间了, 如果把这行代码去掉,偏向锁定就失效了,和上文描述的就一样了。