GeekIBLi

Java-synchronzied底层原理

2021-07-28

synchronzied底层原理

synchronzied四个层级实现

  • Java代码 通过添加synchronzied给对象或者方法或者代码块
  • 字节码层级通过一组 MONITORENTER/MONITOREXIT指令
  • JVM层级:锁升级过程
  • 汇编执行通过 lock comxchg指令保证原子操作

JDK早期,synchronized 叫做重量级锁, 因为申请锁资源必须通过kernel, 系统调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
;hello.asm
;write(int fd, const void *buffer, size_t nbytes)

section data
msg db "Hello", 0xA
len equ $ - msg

section .text
global _start
_start:

mov edx, len
mov ecx, msg
mov ebx, 1 ;文件描述符1 std_out
mov eax, 4 ;write函数系统调用号 4
int 0x80

mov ebx, 0
mov eax, 1 ;exit函数系统调用号
int 0x80

优化后的synchronized如下👇:

Java层级

1
2
3
4
5
6
7
8
public static void main(String[] args) {
Object object = new Object();
System.out.println(ClassLayout.parseInstance(object).toPrintable());

synchronized (object){
System.out.println(ClassLayout.parseInstance(object).toPrintable());
}
}

字节码层级

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// access flags 0x9
public static main([Ljava/lang/String;)V
// parameter args
TRYCATCHBLOCK L0 L1 L2 null
TRYCATCHBLOCK L2 L3 L2 null
L4
LINENUMBER 13 L4
NEW java/lang/Object
DUP
INVOKESPECIAL java/lang/Object.<init> ()V
ASTORE 1
L5
LINENUMBER 14 L5
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKESTATIC org/openjdk/jol/info/ClassLayout.parseInstance (Ljava/lang/Object;)Lorg/openjdk/jol/info/ClassLayout;
INVOKEVIRTUAL org/openjdk/jol/info/ClassLayout.toPrintable ()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L6
LINENUMBER 16 L6
ALOAD 1
DUP
ASTORE 2
MONITORENTER
L0
LINENUMBER 17 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKESTATIC org/openjdk/jol/info/ClassLayout.parseInstance (Ljava/lang/Object;)Lorg/openjdk/jol/info/ClassLayout;
INVOKEVIRTUAL org/openjdk/jol/info/ClassLayout.toPrintable ()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L7
LINENUMBER 18 L7
ALOAD 2
MONITOREXIT
L1
GOTO L8
L2
FRAME FULL [[Ljava/lang/String; java/lang/Object java/lang/Object] [java/lang/Throwable]
ASTORE 3
ALOAD 2
MONITOREXIT
L3
ALOAD 3
ATHROW
L8
LINENUMBER 19 L8
FRAME CHOP 1
RETURN
L9
LOCALVARIABLE args [Ljava/lang/String; L4 L9 0
LOCALVARIABLE object Ljava/lang/Object; L5 L9 1
MAXSTACK = 2
MAXLOCALS = 4
}

主要通过MONITORENTER 和 MONITOREXIT 两个字节码指令控制加锁过程

JVM层级

通过锁升级过程实现加锁;
无锁 -> 偏向锁 -> 自旋锁(轻量级锁 自适应锁)-> 重量级锁
锁升级过程可以查看 锁升级过程 复制理解

汇编指令级别

linux操作系统安装hsdis插件,查看java代码的汇编指令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class T {
static volatile int i = 0;

public static void n() { i++; }

public static synchronized void m() {}

publics static void main(String[] args) {
for(int j=0; j<1000_000; j++) {
m();
n();
}
}
}

执行以下命令:

1
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly T
  • C1 Compile Level 1 (一级优化)
  • C2 Compile Level 2 (二级优化)

找到m() n()方法的汇编码,会看到 lock comxchg …..指令