前言
11 偏向锁的重入 以及 线程1获取偏向锁并释放线程2获取锁 的调试
呵呵 接着前几篇
本文调试一下 一下的几个场景
1. 轻量级的重入
2. 线程1添加了轻量级并释放, 线程2来获取锁
一下内容基于 jdk9 + lldb-1001.0.13.3
另外一下 运行时数据可能是来自于多次调试, 可能会存在运行时数据 对不上的情况, 但是的条理逻辑会在文字中描述清楚的
备注 : 以下调试 增加了vm参数 : -XX:-UseBiasedLocking
轻量级锁重入的测试用例
package com.hx.test04;
/**
* Test26SynchronizeReentrantObject
*
* @author Jerry.X.He <970655147@qq.com>
* @version 1.0
* @date 2020-04-03 15:14
*/
public class Test26SynchronizeReentrantObject implements Cloneable {
// identStr
private String identStr = "xyz";
int f01;
int f02;
int f03;
int f04;
int f05;
// Test26SynchronizeReentrantObject
public static void main(String[] args) throws Exception {
Test26SynchronizeReentrantObject lockObj = new Test26SynchronizeReentrantObject();
synchronized (lockObj) {
synchronized (lockObj) {
// Test26SynchronizeReentrantObject cloned = (Test26SynchronizeReentrantObject) lockObj.clone();
// System.out.println(lockObj.identStr);
}
}
}
}
对应的字节码信息如下, 下面参照可能需要使用到
master:classes jerry$ javap -c com/hx/test04/Test26SynchronizeReentrantObject.class
Compiled from "Test26SynchronizeReentrantObject.java"
public class com.hx.test04.Test26SynchronizeReentrantObject implements java.lang.Cloneable {
int f01;
int f02;
int f03;
int f04;
int f05;
public com.hx.test04.Test26SynchronizeReentrantObject();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String xyz
7: putfield #3 // Field identStr:Ljava/lang/String;
10: return
public static void main(java.lang.String[]) throws java.lang.Exception;
Code:
0: new #4 // class com/hx/test04/Test26SynchronizeReentrantObject
3: dup
4: invokespecial #5 // Method "<init>":()V
7: astore_1
8: aload_1
9: dup
10: astore_2
11: monitorenter
12: aload_1
13: dup
14: astore_3
15: monitorenter
16: aload_3
17: monitorexit
18: goto 28
21: astore 4
23: aload_3
24: monitorexit
25: aload 4
27: athrow
28: aload_2
29: monitorexit
30: goto 40
33: astore 5
35: aload_2
36: monitorexit
37: aload 5
39: athrow
40: return
Exception table:
from to target type
16 18 21 any
21 25 21 any
12 30 33 any
33 37 33 any
}
轻量级锁重入的调试
(lldb) p _active_table._table[9][194]
(address) $0 = 0x00000001048cd600 "XH;"
(lldb) b 0x00000001048cd600
Breakpoint 3: address = 0x00000001048cd600
(lldb) c
Process 1019 resuming
Process 1019 stopped
* thread #5, stop reason = breakpoint 3.1
frame #0: 0x00000001048cd600
-> 0x1048cd600: popq %rax
0x1048cd601: cmpq (%rax), %rax
0x1048cd604: xorl %esi, %esi
0x1048cd606: movq -0x48(%rbp), %rcx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x0000000747bb8798
rbx = 0x00000000000000c2
rcx = 0x0000000000000008
rdx = 0x0000000747bb87b8
rdi = 0x000000010100f220
rsi = 0x000070000a2595c0
rbp = 0x000070000a259670
rsp = 0x000070000a259620
r8 = 0x0000000000000000
r9 = 0x0000000000000020
r10 = 0x000000010430b270 libjvm.dylib`TemplateInterpreter::_active_table + 18432
r11 = 0x00006fff09249400
r12 = 0x0000000000000000
r13 = 0x000000011c96ff93
r14 = 0x000070000a2596a8
r15 = 0x000000010100f220
rip = 0x00000001048cd600
rflags = 0x0000000000000206
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) p ((oopDesc*)0x0000000747bb8798)->print()
com.hx.test04.Test26SynchronizeReentrantObject
{0x0000000747bb8798} - klass: 'com/hx/test04/Test26SynchronizeReentrantObject'
- ---- fields (total size 5 words):
- 'f01' 'I' @12 0
- 'f02' 'I' @16 0
- 'f03' 'I' @20 0
- 'f04' 'I' @24 0
- 'f05' 'I' @28 0
- private 'identStr' 'Ljava/lang/String;' @32 "xyz"{0x0000000747bb87c0} (e8f770f8 0)
(lldb) p ((oopDesc*)0x0000000747bb8798)->has_locker()
error: no member named 'has_locker' in 'oopDesc'
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->has_locker()
(bool) $1 = false
(lldb) x 0x000070000a259620
0x70000a259620: 98 87 bb 47 07 00 00 00 28 96 25 0a 00 70 00 00 ..?G....(.%..p..
0x70000a259630: 8c ff 96 1c 01 00 00 00 a8 96 25 0a 00 70 00 00 .?......?.%..p..
// continue, 之后 断点停留在了 第二个 monitorenter
(lldb) c
Process 1019 resuming
Process 1019 stopped
* thread #5, stop reason = breakpoint 3.1
frame #0: 0x00000001048cd600
-> 0x1048cd600: popq %rax
0x1048cd601: cmpq (%rax), %rax
0x1048cd604: xorl %esi, %esi
0x1048cd606: movq -0x48(%rbp), %rcx
Target 0: (java) stopped.
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->has_locker()
(bool) $2 = true
(lldb) re r
General Purpose Registers:
rax = 0x0000000747bb8798
rbx = 0x00000000000000c2
rcx = 0x0000000747bb8798
rdx = 0x000070000a259628
rdi = 0x000000010100f220
rsi = 0x000070000a259618
rbp = 0x000070000a259670
rsp = 0x000070000a259610
r8 = 0x0000000000000000
r9 = 0x0000000000000020
r10 = 0x000000010430b270 libjvm.dylib`TemplateInterpreter::_active_table + 18432
r11 = 0x00006fff09249400
r12 = 0x0000000000000000
r13 = 0x000000011c96ff97
r14 = 0x000070000a2596a8
r15 = 0x000000010100f220
rip = 0x00000001048cd600
rflags = 0x0000000000000202
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) x 0x000070000a259610 -c 0x30
0x70000a259610: 98 87 bb 47 07 00 00 00 01 00 00 00 00 00 00 00 ..?G............
0x70000a259620: 98 87 bb 47 07 00 00 00 18 96 25 0a 00 70 00 00 ..?G......%..p..
0x70000a259630: 94 ff 96 1c 01 00 00 00 a8 96 25 0a 00 70 00 00 .?......?.%..p..
(lldb) b 0x1048cd663
Breakpoint 4: address = 0x00000001048cd663
(lldb) c
Process 1019 resuming
Process 1019 stopped
* thread #5, stop reason = breakpoint 4.1
frame #0: 0x00000001048cd663
-> 0x1048cd663: movq 0x8(%rsi), %rcx
0x1048cd667: movl $0x1, %eax
0x1048cd66c: orq (%rcx), %rax
0x1048cd66f: movq %rax, (%rsi)
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x00000001048cd667
-> 0x1048cd667: movl $0x1, %eax
0x1048cd66c: orq (%rcx), %rax
0x1048cd66f: movq %rax, (%rsi)
0x1048cd672: lock
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x00000001048cd66c
-> 0x1048cd66c: orq (%rcx), %rax
0x1048cd66f: movq %rax, (%rsi)
0x1048cd672: lock
0x1048cd673: cmpxchgq %rsi, (%rcx)
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x00000001048cd66f
-> 0x1048cd66f: movq %rax, (%rsi)
0x1048cd672: lock
0x1048cd673: cmpxchgq %rsi, (%rcx)
0x1048cd677: je 0x1048cd8f0
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x00000001048cd672
-> 0x1048cd672: lock
0x1048cd673: cmpxchgq %rsi, (%rcx)
0x1048cd677: je 0x1048cd8f0
0x1048cd67d: subq %rsp, %rax
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x000070000a259619
rbx = 0x00000000000000c2
rcx = 0x0000000747bb8798
rdx = 0x000070000a259628
rdi = 0x000000010100f220
rsi = 0x000070000a259608
rbp = 0x000070000a259670
rsp = 0x000070000a259608
r8 = 0x0000000000000000
r9 = 0x0000000000000020
r10 = 0x000000010430b270 libjvm.dylib`TemplateInterpreter::_active_table + 18432
r11 = 0x00006fff09249400
r12 = 0x0000000000000000
r13 = 0x000000011c96ff98
r14 = 0x000070000a2596a8
r15 = 0x000000010100f220
rip = 0x00000001048cd672
rflags = 0x0000000000000202
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x00000001048cd677
-> 0x1048cd677: je 0x1048cd8f0
0x1048cd67d: subq %rsp, %rax
0x1048cd680: andq $-0xff9, %rax ; imm = 0xF007
0x1048cd687: movq %rax, (%rsi)
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x00000001048cd67d
-> 0x1048cd67d: subq %rsp, %rax
0x1048cd680: andq $-0xff9, %rax ; imm = 0xF007
0x1048cd687: movq %rax, (%rsi)
0x1048cd68a: je 0x1048cd8f0
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x000070000a259618
rbx = 0x00000000000000c2
rcx = 0x0000000747bb8798
rdx = 0x000070000a259628
rdi = 0x000000010100f220
rsi = 0x000070000a259608
rbp = 0x000070000a259670
rsp = 0x000070000a259608
r8 = 0x0000000000000000
r9 = 0x0000000000000020
r10 = 0x000000010430b270 libjvm.dylib`TemplateInterpreter::_active_table + 18432
r11 = 0x00006fff09249400
r12 = 0x0000000000000000
r13 = 0x000000011c96ff98
r14 = 0x000070000a2596a8
r15 = 0x000000010100f220
rip = 0x00000001048cd67d
rflags = 0x0000000000000202
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x00000001048cd680
-> 0x1048cd680: andq $-0xff9, %rax ; imm = 0xF007
0x1048cd687: movq %rax, (%rsi)
0x1048cd68a: je 0x1048cd8f0
0x1048cd690: callq 0x1048cd69a
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x00000001048cd687
-> 0x1048cd687: movq %rax, (%rsi)
0x1048cd68a: je 0x1048cd8f0
0x1048cd690: callq 0x1048cd69a
0x1048cd695: jmp 0x1048cd8f0
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x00000001048cd68a
-> 0x1048cd68a: je 0x1048cd8f0
0x1048cd690: callq 0x1048cd69a
0x1048cd695: jmp 0x1048cd8f0
0x1048cd69a: leaq 0x8(%rsp), %rax
Target 0: (java) stopped.
(lldb) stepi
Process 1019 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x00000001048cd8f0
-> 0x1048cd8f0: movq %r13, -0x40(%rbp)
0x1048cd8f4: movl %eax, -0x16000(%rsp)
0x1048cd8fb: movzbl (%r13), %ebx
0x1048cd900: movabsq $0x10430b270, %r10 ; imm = 0x10430B270
Target 0: (java) stopped.
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->has_locker()
(bool) $3 = true
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->locker()
(BasicLock *) $4 = 0x000070000a259618
(lldb) re r
General Purpose Registers:
rax = 0x0000000000000000
rbx = 0x00000000000000c2
rcx = 0x0000000747bb8798
rdx = 0x000070000a259628
rdi = 0x000000010100f220
rsi = 0x000070000a259608
rbp = 0x000070000a259670
rsp = 0x000070000a259608
r8 = 0x0000000000000000
r9 = 0x0000000000000020
r10 = 0x000000010430b270 libjvm.dylib`TemplateInterpreter::_active_table + 18432
r11 = 0x00006fff09249400
r12 = 0x0000000000000000
r13 = 0x000000011c96ff98
r14 = 0x000070000a2596a8
r15 = 0x000000010100f220
rip = 0x00000001048cd8f0
rflags = 0x0000000000000246
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) x 0x000070000a259608 -c 0x40
0x70000a259608: 00 00 00 00 00 00 00 00 98 87 bb 47 07 00 00 00 ..........?G....
0x70000a259618: 01 00 00 00 00 00 00 00 98 87 bb 47 07 00 00 00 ..........?G....
0x70000a259628: 08 96 25 0a 00 70 00 00 94 ff 96 1c 01 00 00 00 ..%..p...?......
0x70000a259638: a8 96 25 0a 00 70 00 00 88 00 97 1c 01 00 00 00 ?.%..p..........
相关汇编代码, 请参见 09 给对象添加偏向锁的调试
这里在 monitorenter 的地方打了一个断点, 并且输出了 当前 lockObj 的相关信息之后, 直接 continue, 断点停在了 第二个 monitorenter
我们可以整理一些结论
1. 在第一个断点的时候, lockObj 没有锁, 就一个 0x001, 第二个断点的时候 已经加上了mian线程 获取了 lockObj 的轻量级锁
2. 第二个断点相比于 第一个断点, [0x70000a259618 - 0x70000a259628) 增加了一个 BasicLockObject 关联 lockObj 对象
然后 来到了第二个断点, 增加了一个 对应的 BasicLockObject 并更新了 BasicLockObject.obj
来到这边变的业务处理, rax 初始化为1, 和 rcx(lockObj)进行了一个 or, 因为 rcx(lockObj) 现在 mark 记录的是 BasicLockObject 的地址(第一个断点的时候加的轻量级锁)(最后一个bit肯定为0), 所以 rax 现在为 &BasicLockObject + 1
然后进行 cas(rsi, rcx, rax), 其中 rsi 存储的是这一次加锁的 BasicLockObject 的地址
因为 rcx 对应的地址的数据 和 rax 不相同, 所以 cas 失败
cas 操作失败之后, rax 为 rcx 的地址的值, 就是 第一次加锁的 BasicLockObject 的地址
然后来到后面, rax = rax - rsp 结果为 0x10
然后 and 了一下 0b1111 0000 0000 0111, 之后 rax 为 0, goto done, 重入加锁成功
rax 和 rsp 的 delta 可以再 0b0000 0000 0000 0000 - 0b0000 1111 1111 1000 这个范围内, 视为 轻量级锁的重入
对了 还有一个细节, 这里如果是轻量级锁重入的场景的话 会设置 当前 BasicLockObject.lock.displaced_header 为 0[这里的rax一定为0]
为什么会挑这个 (zero_bits - os::vm_page_size()) = 7 - 4096 = -4089 ?, 呵呵 这里暂时还看不太明白, 我的理解应该是会和 线程栈帧的大小有关系呀
轻量级锁的退出
(lldb) p _active_table._table[9][195]
(address) $1 = 0x000000010584f9e0 "XH;"
(lldb) b 0x000000010584f9e1
Breakpoint 5: address = 0x000000010584f9e1
(lldb) c
Process 1049 resuming
Process 1049 stopped
* thread #5, stop reason = breakpoint 5.1
frame #0: 0x000000010584f9e1
-> 0x10584f9e1: cmpq (%rax), %rax
0x10584f9e4: movq -0x48(%rbp), %rsi
0x10584f9e8: leaq -0x48(%rbp), %rdx
0x10584f9ec: jmp 0x10584f9fc
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x0000000747bb8798
rbx = 0x00000000000000c3
rcx = 0x0000000747bb8798
rdx = 0x0000700002548628
rdi = 0x000000010500cc20
rsi = 0x0000700002548608
rbp = 0x0000700002548670
rsp = 0x0000700002548608
r8 = 0x0000000000000000
r9 = 0x0000000000000020
r10 = 0x0000000103b0aa70 libjvm.dylib`TemplateInterpreter::_active_table + 16384
r11 = 0x0000000000000200
r12 = 0x0000000000000000
r13 = 0x000000011c7f1f99
r14 = 0x00007000025486a8
r15 = 0x000000010500cc20
rip = 0x000000010584f9e1
rflags = 0x0000000000000206
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) p ((oopDesc*)0x0000000747bb8798)->print()
com.hx.test04.Test26SynchronizeReentrantObject
{0x0000000747bb8798} - klass: 'com/hx/test04/Test26SynchronizeReentrantObject'
- ---- fields (total size 5 words):
- 'f01' 'I' @12 0
- 'f02' 'I' @16 0
- 'f03' 'I' @20 0
- 'f04' 'I' @24 0
- 'f05' 'I' @28 0
- private 'identStr' 'Ljava/lang/String;' @32 "xyz"{0x0000000747bb87c0} (e8f770f8 0)
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->has_locker()
(bool) $2 = true
(lldb) x 0x0000700002548608 -c 0x40
0x700002548608: 00 00 00 00 00 00 00 00 98 87 bb 47 07 00 00 00 ..........?G....
0x700002548618: 01 00 00 00 00 00 00 00 98 87 bb 47 07 00 00 00 ..........?G....
0x700002548628: 08 86 54 02 00 70 00 00 98 1f 7f 1c 01 00 00 00 ..T..p..........
0x700002548638: a8 86 54 02 00 70 00 00 88 20 7f 1c 01 00 00 00 ?.T..p... ......
// continue, 之后 断点停留在了 第二个 monitorexit
(lldb) c
Process 1049 resuming
Process 1049 stopped
* thread #5, stop reason = breakpoint 5.1
frame #0: 0x000000010584f9e1
-> 0x10584f9e1: cmpq (%rax), %rax
0x10584f9e4: movq -0x48(%rbp), %rsi
0x10584f9e8: leaq -0x48(%rbp), %rdx
0x10584f9ec: jmp 0x10584f9fc
Target 0: (java) stopped.
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->has_locker()
(bool) $3 = true
(lldb) x 0x0000700002548608 -c 0x40
0x700002548608: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x700002548618: 01 00 00 00 00 00 00 00 98 87 bb 47 07 00 00 00 ..........?G....
0x700002548628: 08 86 54 02 00 70 00 00 99 1f 7f 1c 01 00 00 00 ..T..p..........
0x700002548638: a8 86 54 02 00 70 00 00 88 20 7f 1c 01 00 00 00 ?.T..p... ......
(lldb) b 0x10584fcdd
Breakpoint 6: address = 0x000000010584fcdd
(lldb) c
Process 1049 resuming
Process 1049 stopped
* thread #5, stop reason = breakpoint 6.1
frame #0: 0x000000010584fcdd
-> 0x10584fcdd: leaq (%rsi), %rax
0x10584fce0: movq 0x8(%rsi), %rcx
0x10584fce4: movq $0x0, 0x8(%rsi)
0x10584fcec: movq (%rax), %rdx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x0000000747bb8798
rbx = 0x00000000000000c3
rcx = 0x000000011c7f2000
rdx = 0x0000700002548628
rdi = 0x000000010500cc20
rsi = 0x0000700002548618
rbp = 0x0000700002548670
rsp = 0x0000700002548600
r8 = 0x0000000000000000
r9 = 0x0000000000000020
r10 = 0x0000000103b0aa70 libjvm.dylib`TemplateInterpreter::_active_table + 16384
r11 = 0x0000000000000200
r12 = 0x0000000000000000
r13 = 0x000000011c7f1fa5
r14 = 0x00007000025486a8
r15 = 0x000000010500cc20
rip = 0x000000010584fcdd
rflags = 0x0000000000000246
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x000000010584fce0
-> 0x10584fce0: movq 0x8(%rsi), %rcx
0x10584fce4: movq $0x0, 0x8(%rsi)
0x10584fcec: movq (%rax), %rdx
0x10584fcef: testq %rdx, %rdx
Target 0: (java) stopped.
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x000000010584fce4
-> 0x10584fce4: movq $0x0, 0x8(%rsi)
0x10584fcec: movq (%rax), %rdx
0x10584fcef: testq %rdx, %rdx
0x10584fcf2: je 0x10584ff67
Target 0: (java) stopped.
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x000000010584fcec
-> 0x10584fcec: movq (%rax), %rdx
0x10584fcef: testq %rdx, %rdx
0x10584fcf2: je 0x10584ff67
0x10584fcf8: lock
Target 0: (java) stopped.
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x000000010584fcef
-> 0x10584fcef: testq %rdx, %rdx
0x10584fcf2: je 0x10584ff67
0x10584fcf8: lock
0x10584fcf9: cmpxchgq %rdx, (%rcx)
Target 0: (java) stopped.
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x000000010584fcf2
-> 0x10584fcf2: je 0x10584ff67
0x10584fcf8: lock
0x10584fcf9: cmpxchgq %rdx, (%rcx)
0x10584fcfd: je 0x10584ff67
Target 0: (java) stopped.
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x000000010584fcf8
-> 0x10584fcf8: lock
0x10584fcf9: cmpxchgq %rdx, (%rcx)
0x10584fcfd: je 0x10584ff67
0x10584fd03: movq %rcx, 0x8(%rsi)
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x0000700002548618
rbx = 0x00000000000000c3
rcx = 0x0000000747bb8798
rdx = 0x0000000000000001
rdi = 0x000000010500cc20
rsi = 0x0000700002548618
rbp = 0x0000700002548670
rsp = 0x0000700002548600
r8 = 0x0000000000000000
r9 = 0x0000000000000020
r10 = 0x0000000103b0aa70 libjvm.dylib`TemplateInterpreter::_active_table + 16384
r11 = 0x0000000000000200
r12 = 0x0000000000000000
r13 = 0x000000011c7f1fa5
r14 = 0x00007000025486a8
r15 = 0x000000010500cc20
rip = 0x000000010584fcf8
rflags = 0x0000000000000202
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x000000010584fcfd
-> 0x10584fcfd: je 0x10584ff67
0x10584fd03: movq %rcx, 0x8(%rsi)
0x10584fd07: callq 0x10584fd11
0x10584fd0c: jmp 0x10584ff67
Target 0: (java) stopped.
(lldb) stepi
Process 1049 stopped
* thread #5, stop reason = instruction step into
frame #0: 0x000000010584ff67
-> 0x10584ff67: movq -0x40(%rbp), %r13
0x10584ff6b: popq %rax
0x10584ff6c: movzbl 0x1(%r13), %ebx
0x10584ff71: incq %r13
Target 0: (java) stopped.
(lldb) p ((oopDesc*)0x0000000747bb8798)->mark()->has_locker()
(bool) $4 = false
(lldb) x 0x0000700002548600 -c 0x40
0x700002548600: 98 87 bb 47 07 00 00 00 00 00 00 00 00 00 00 00 ..?G............
0x700002548610: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................
0x700002548620: 00 00 00 00 00 00 00 00 08 86 54 02 00 70 00 00 ..........T..p..
0x700002548630: a5 1f 7f 1c 01 00 00 00 a8 86 54 02 00 70 00 00 ?.......?.T..p..
断点来到第一个 monitorexit 的时候, 此时 lockObj 的轻量级锁被 main 持有, 并且 main 重入了一次
查看一下 栈顶的信息, 和 main 重入获取 lockObj 的结果一致, 第一个 BasicLockObject.lock.displaced_header 存放的是 lockObj之前的结果, 第二个 BasicLockObject.lock.displaced_header 里面存放的是 0
然后 continue, 到达第二个 monitorexit
第一个 monitorexit 因为对应的是 重入的 monitorenter, 因此 没有做太多的事情, 仅仅是单纯的吧 第二个 BasicLockObject.obj 置空了
然后 到达 第二个 monitorexit 业务处理之后, 吧 第一个 BasicLockObject.obj 置空了, 并且吧 第一个 BasicLockObject.lock.displaced_header cas 替换到了 lockObj 的对象头里面
然后这个时候 再来查看 lockObj 的轻量级锁的相关信息, 就已经没有被 main 线程持有了
查看栈的内存信息, 可以发现 两个 BasicLockObject.obj 都已经被置空了
轻量级锁线程同步块执行完成 其他线程尝试加锁
package com.hx.test04;
/**
* Test27MultiThreadInBiasLock
*
* @author Jerry.X.He <970655147@qq.com>
* @version 1.0
* @date 2020-04-03 15:14
*/
public class Test27MultiThreadInBiasLock implements Cloneable {
// identStr
private String identStr = "xyz";
int f01;
int f02;
int f03;
int f04;
int f05;
// Test25SynchronizeObject
public static void main(String[] args) throws Exception {
Test27MultiThreadInBiasLock lockObj = new Test27MultiThreadInBiasLock();
doClone(lockObj);
synchronized (lockObj) {
}
new Thread() {
@Override
public void run() {
doClone(lockObj);
synchronized (lockObj) {
}
}
}.start();
Test25SynchronizeObject.sleep(2000);
}
// doClone
private static void doClone(Test27MultiThreadInBiasLock obj) {
try {
obj.clone();
} catch (Exception e) {
e.printStackTrace();
}
}
}
调试信息如下
(lldb) br set -f jvm.cpp -l 627 -c ((obj()->klass()->is_instance_klass())&&(((InstanceKlass*)obj()->klass())->java_fields_count()==6))
Breakpoint 3: where = libjvm.dylib`::JVM_Clone(JNIEnv *, jobject) + 516 at jvm.cpp:627:28, address = 0x0000000103171ab4
(lldb) p _active_table._table[9][194]
(address) $0 = 0x000000010504f600 "XH;"
(lldb) c
Process 1619 resuming
Process 1619 stopped
* thread #5, stop reason = breakpoint 3.1
frame #0: 0x0000000103171ab4 libjvm.dylib`::JVM_Clone(env=0x0000000100808648, handle=0x000070000deca5c8) at jvm.cpp:627:28
624 JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
625 JVMWrapper("JVM_Clone");
626 Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
-> 627 const KlassHandle klass (THREAD, obj->klass());
628 JvmtiVMObjectAllocEventCollector oam;
629
630 #ifdef ASSERT
Target 0: (java) stopped.
(lldb) c
Process 1619 resuming
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = breakpoint 3.1
frame #0: 0x0000000103171ab4 libjvm.dylib`::JVM_Clone(env=0x0000000114851848, handle=0x000070001002d5e0) at jvm.cpp:627:28
624 JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
625 JVMWrapper("JVM_Clone");
626 Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
-> 627 const KlassHandle klass (THREAD, obj->klass());
628 JvmtiVMObjectAllocEventCollector oam;
629
630 #ifdef ASSERT
Target 0: (java) stopped.
(lldb) b 0x000000010504f600
Breakpoint 4: address = 0x000000010504f600
// continue 之后进入 Thread-0 的 monitorenter
(lldb) c
Process 1619 resuming
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = breakpoint 4.1
frame #0: 0x000000010504f600
-> 0x10504f600: popq %rax
0x10504f601: cmpq (%rax), %rax
0x10504f604: xorl %esi, %esi
0x10504f606: movq -0x48(%rbp), %rcx
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x0000000747bb8f68
rbx = 0x00000000000000c2
rcx = 0x00000000000000cb
rdx = 0x0000000000000000
rdi = 0x000000010500b220
rsi = 0x000070001002d650
rbp = 0x000070001002d6f8
rsp = 0x000070001002d6a8
r8 = 0x0000000000000001
r9 = 0x0000000747bf9cb8
r10 = 0x0000000103b0b270 libjvm.dylib`TemplateInterpreter::_active_table + 18432
r11 = 0x000070001002d5e0
r12 = 0x0000000000000000
r13 = 0x000000011c75e845
r14 = 0x000070001002d718
r15 = 0x0000000114851620
rip = 0x000000010504f600
rflags = 0x0000000000000202
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) p ((oopDesc*)0x0000000747bb8f68)->print()
com.hx.test04.Test27MultiThreadInBiasLock
{0x0000000747bb8f68} - klass: 'com/hx/test04/Test27MultiThreadInBiasLock'
- ---- fields (total size 5 words):
- 'f01' 'I' @12 0
- 'f02' 'I' @16 0
- 'f03' 'I' @20 0
- 'f04' 'I' @24 0
- 'f05' 'I' @28 0
- private 'identStr' 'Ljava/lang/String;' @32 "xyz"{0x0000000747bb8f90} (e8f771f2 0)
(lldb) p ((oopDesc*)0x0000000747bb8f68)->mark()->has_locker()
(bool) $3 = false
(lldb) b 0x10504f663
Breakpoint 5: address = 0x000000010504f663
(lldb) c
Process 1619 resuming
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = breakpoint 5.1
frame #0: 0x000000010504f663
-> 0x10504f663: movq 0x8(%rsi), %rcx
0x10504f667: movl $0x1, %eax
0x10504f66c: orq (%rcx), %rax
0x10504f66f: movq %rax, (%rsi)
Target 0: (java) stopped.
(lldb) stepi
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = instruction step into
frame #0: 0x000000010504f667
-> 0x10504f667: movl $0x1, %eax
0x10504f66c: orq (%rcx), %rax
0x10504f66f: movq %rax, (%rsi)
0x10504f672: lock
Target 0: (java) stopped.
(lldb) stepi
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = instruction step into
frame #0: 0x000000010504f66c
-> 0x10504f66c: orq (%rcx), %rax
0x10504f66f: movq %rax, (%rsi)
0x10504f672: lock
0x10504f673: cmpxchgq %rsi, (%rcx)
Target 0: (java) stopped.
(lldb) stepi
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = instruction step into
frame #0: 0x000000010504f66f
-> 0x10504f66f: movq %rax, (%rsi)
0x10504f672: lock
0x10504f673: cmpxchgq %rsi, (%rcx)
0x10504f677: je 0x10504f8f0
Target 0: (java) stopped.
(lldb) stepi
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = instruction step into
frame #0: 0x000000010504f672
-> 0x10504f672: lock
0x10504f673: cmpxchgq %rsi, (%rcx)
0x10504f677: je 0x10504f8f0
0x10504f67d: subq %rsp, %rax
Target 0: (java) stopped.
(lldb) re r
General Purpose Registers:
rax = 0x0000000000000001
rbx = 0x00000000000000c2
rcx = 0x0000000747bb8f68
rdx = 0x000070001002d6b0
rdi = 0x000000010500b220
rsi = 0x000070001002d6a0
rbp = 0x000070001002d6f8
rsp = 0x000070001002d6a0
r8 = 0x0000000000000001
r9 = 0x0000000747bf9cb8
r10 = 0x0000000103b0b270 libjvm.dylib`TemplateInterpreter::_active_table + 18432
r11 = 0x000070001002d5e0
r12 = 0x0000000000000000
r13 = 0x000000011c75e846
r14 = 0x000070001002d718
r15 = 0x0000000114851620
rip = 0x000000010504f672
rflags = 0x0000000000000202
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
(lldb) x 0x0000000747bb8f68
0x747bb8f68: 01 00 00 00 00 00 00 00 86 1f 01 f8 00 00 00 00 ...........?....
0x747bb8f78: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
(lldb) stepi
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = instruction step into
frame #0: 0x000000010504f677
-> 0x10504f677: je 0x10504f8f0
0x10504f67d: subq %rsp, %rax
0x10504f680: andq $-0xff9, %rax ; imm = 0xF007
0x10504f687: movq %rax, (%rsi)
Target 0: (java) stopped.
(lldb) stepi
Process 1619 stopped
* thread #38, name = 'Java: Thread-0', stop reason = instruction step into
frame #0: 0x000000010504f8f0
-> 0x10504f8f0: movq %r13, -0x40(%rbp)
0x10504f8f4: movl %eax, -0x16000(%rsp)
0x10504f8fb: movzbl (%r13), %ebx
0x10504f900: movabsq $0x103b0b270, %r10 ; imm = 0x103B0B270
Target 0: (java) stopped.
可以看到 continue 之后, Thread-0 来获取 lockObj 的锁的时候
lockObj 上面的轻量级锁已经被 main线程 释放了, 并且 对象头也替换成了 加锁之前的对象头了
然后所以这里的 Thread-0 获取锁 相当于又是走的一次 获取 lockObj 的轻量级锁的过程, 并且加锁成功
完
参考
11 偏向锁的重入 以及 线程1获取偏向锁并释放线程2获取锁 的调试