youyichannel

志于道,据于德,依于仁,游于艺!

0%

Synchronized全解读-01

Synchronized的使用方式

Synchronized作用于普通方法、静态方法、同步代码块。通过javap -v命令深入查看。

代码示例:

public class SyncUsingWay {

/**
* 普通方法
* 锁对象:实例对象,谁调用这个方法,锁就作用于谁身上
*/
public synchronized void syncMethod() {
System.out.println("Synchronized Method");
}

/**
* 静态方法
* 锁对象:对象的class,全局唯一
* 类型 包括 类的class文件的二进制文件最终都加载到了运行时数据区的方法区
*/
public synchronized static void staticSyncMethod() {
System.out.println("Static Synchronized Method");
}

public void method() {
// 静态代码块
synchronized (this) {
System.out.println("Method");
}
}
}

编译之后,使用javap -v SyncUsingWay.class查看信息:

Classfile /Users/codejuzi/Documents/CodeWorkSpace/Practice/juc-demo/target/classes/com/juzi/juc/sync/SyncUsingWay.class
Last modified 2023-12-1; size 839 bytes
MD5 checksum 594bba00a6d14034bd77c93025a9dd13
Compiled from "SyncUsingWay.java"
public class com.juzi.juc.sync.SyncUsingWay
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #8.#25 // java/lang/Object."<init>":()V
#2 = Fieldref #26.#27 // java/lang/System.out:Ljava/io/PrintStream;
#3 = String #28 // Synchronized Method
#4 = Methodref #29.#30 // java/io/PrintStream.println:(Ljava/lang/String;)V
#5 = String #31 // Static Synchronized Method
#6 = String #32 // Method
#7 = Class #33 // com/juzi/juc/sync/SyncUsingWay
#8 = Class #34 // java/lang/Object
#9 = Utf8 <init>
#10 = Utf8 ()V
#11 = Utf8 Code
#12 = Utf8 LineNumberTable
#13 = Utf8 LocalVariableTable
#14 = Utf8 this
#15 = Utf8 Lcom/juzi/juc/sync/SyncUsingWay;
#16 = Utf8 syncMethod
#17 = Utf8 staticSyncMethod
#18 = Utf8 method
#19 = Utf8 StackMapTable
#20 = Class #33 // com/juzi/juc/sync/SyncUsingWay
#21 = Class #34 // java/lang/Object
#22 = Class #35 // java/lang/Throwable
#23 = Utf8 SourceFile
#24 = Utf8 SyncUsingWay.java
#25 = NameAndType #9:#10 // "<init>":()V
#26 = Class #36 // java/lang/System
#27 = NameAndType #37:#38 // out:Ljava/io/PrintStream;
#28 = Utf8 Synchronized Method
#29 = Class #39 // java/io/PrintStream
#30 = NameAndType #40:#41 // println:(Ljava/lang/String;)V
#31 = Utf8 Static Synchronized Method
#32 = Utf8 Method
#33 = Utf8 com/juzi/juc/sync/SyncUsingWay
#34 = Utf8 java/lang/Object
#35 = Utf8 java/lang/Throwable
#36 = Utf8 java/lang/System
#37 = Utf8 out
#38 = Utf8 Ljava/io/PrintStream;
#39 = Utf8 java/io/PrintStream
#40 = Utf8 println
#41 = Utf8 (Ljava/lang/String;)V
{
public com.juzi.juc.sync.SyncUsingWay();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 6: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/juzi/juc/sync/SyncUsingWay;

public synchronized void syncMethod();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Synchronized Method
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 13: 0
line 14: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lcom/juzi/juc/sync/SyncUsingWay;

public static synchronized void staticSyncMethod();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=0, args_size=0
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #5 // String Static Synchronized Method
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 22: 0
line 23: 8

public void method();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: ldc #6 // String Method
9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
12: aload_1
13: monitorexit
14: goto 22
17: astore_2
18: aload_1
19: monitorexit
20: aload_2
21: athrow
22: return
Exception table:
from to target type
4 14 17 any
17 20 17 any
LineNumberTable:
line 27: 0
line 28: 4
line 29: 12
line 30: 22
LocalVariableTable:
Start Length Slot Name Signature
0 23 0 this Lcom/juzi/juc/sync/SyncUsingWay;
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 17
locals = [ class com/juzi/juc/sync/SyncUsingWay, class java/lang/Object ]
stack = [ class java/lang/Throwable ]
frame_type = 250 /* chop */
offset_delta = 4
}
SourceFile: "SyncUsingWay.java"

SyncMethod普通同步方法

public synchronized void syncMethod();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Synchronized Method
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 13: 0
line 14: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lcom/juzi/juc/sync/SyncUsingWay;

flag中ACC_SYNCHRONIZED是加锁的标志,编译期生成。

StaticSyncMethod静态同步方法中flag部分相比于普通同步方法增加了ACC_STATIC。

method同步代码块的字节码信息的flag信息中并没有任何与synchronized有关的标志。但是在Code区域中,存在monitorentermonitorexit

3: monitorenter
...
13: monitorexit
...
19: monitorexit
...
Exception table:
...
  • monitorenter:标志进入同步代码块(临界范围内,锁的原子内部)
  • 第一个monitorexit:正常退出同步代码块
  • 第二个monitorexit:异常情况下的退出同步代码块。在异常情况下,JVM依然可以正常退出锁。
  • Exception table:在异常情况下配合JVM退出锁

资料:https://www.bilibili.com/video/BV1dv411c79B/ 强推 河北王校长