- Synchronized用来给对象加锁,一段简单的示例代码:
public class SynchronizedDemo {
//实例方法,同步方法,加锁对象是当前实例
public synchronized void lockInstance() {
System.out.println("Instance");
}
public void lockThis() {
synchronized(this) { //明确指定this作为加锁对象
System.out.println("'This'");
}
}
//另外,如果是static方法的话,加锁对象就是这个方法的class对象了,也就是为SynchronizedDemo生成的java.lang.Class的实例
}
- 使用javap看lockInstance()字节码
这个方法是实例方法,同时ACC_SYNCHRONIZED说明是同步方法,执行该方法使用monitorenter、monitorexit对实例对象进行加解锁
public synchronized void lockInstance();
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 Instance
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 4: 0
line 5: 8
- 使用javap看lockThis()字节码
更直观的,明确指定synchronized的作用对象
public void lockThis();
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 #5 // String 'This'
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 8: 0
line 9: 4
line 10: 12
line 11: 22
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 17
locals = [ class SynchronizedDemo, class java/lang/Object ]
stack = [ class java/lang/Throwable ]
frame_type = 250 /* chop */
offset_delta = 4
- 一个对象实例创建出来时,处于无锁状态
- synchorinzed在JVM层面是通过monitorenter和monitorexit来完成的
-
monitorenter的加锁过程
-
如果锁膨胀为重量级锁,获取过程如下
- monitorexit解锁过程
以上通过《深入理解Java虚拟机》和其它博客学习而来,本人理解上可能存在偏差,如有不当之处欢迎指正,不胜感激。