synchronized 如何实现同步
- 编译Java生成.class文件
#Sync.java
package com.vip.leona.demo;
/**
* Created by hyson 28/03/2018 8:12 AM
*/
public class Sync {
public synchronized void f() {
}
public void g() {
synchronized (this) {
}
}
}
//编译生成Sync.class
javac Sync.java
//执行命令生成.class可读文件,生成完整文件如下所示
javap -v -l -p -c -s -sysinfo -classpath -bootclasspath Sync.class > Sync.txt
Classfile /Users/hyson/Documents/ws/workspace-vip/leona/src/test/java/com/vip/leona/demo/Sync.class
Last modified Mar 28, 2018; size 399 bytes
MD5 checksum 84d7feb31fcc5935d8afb9e2a2575248
Compiled from "Sync.java"
public class com.vip.leona.demo.Sync
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#16 // java/lang/Object."<init>":()V
#2 = Class #17 // com/vip/leona/demo/Sync
#3 = Class #18 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 f
#9 = Utf8 g
#10 = Utf8 StackMapTable
#11 = Class #17 // com/vip/leona/demo/Sync
#12 = Class #18 // java/lang/Object
#13 = Class #19 // java/lang/Throwable
#14 = Utf8 SourceFile
#15 = Utf8 Sync.java
#16 = NameAndType #4:#5 // "<init>":()V
#17 = Utf8 com/vip/leona/demo/Sync
#18 = Utf8 java/lang/Object
#19 = Utf8 java/lang/Throwable
{
public com.vip.leona.demo.Sync();
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
public synchronized void f();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 8: 0
public void g();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: aload_1
5: monitorexit
6: goto 14
9: astore_2
10: aload_1
11: monitorexit
12: aload_2
13: athrow
14: return
Exception table:
from to target type
4 6 9 any
9 12 9 any
LineNumberTable:
line 11: 0
line 12: 4
line 13: 14
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 9
locals = [ class com/vip/leona/demo/Sync, class java/lang/Object ]
stack = [ class java/lang/Throwable ]
frame_type = 250 /* chop */
offset_delta = 4
}
SourceFile: "Sync.java"
可见:synchronized
- 在方法上,实现方式为多一个标记位:ACC_SYNCHRONIZED
- 在语句块中,monitorenter,monitorexit组合实现同步
分析monitor情况
monitorenter:通过对象引用获取排它锁,这里有3种可能的场景:
- 没有其他的线程锁该对象,会在这个对象上加锁,然后执行后面的指令
- 如果该对象被其他线程加锁,会等待其他线程释放该对象锁
- 如果当前线程已经拥有该对象锁,计数器已经+1,当计数器变回0时,才会释放该对象锁
monitorexit:释放之前获得的排他锁。如果其他线程等待该对象锁释放,一个等待线程将可以获得锁并继续执行
- 单线程可以锁住对象很多次,运行是会维持一数字即该对象被当前线程锁住的次数,次数为0时才表示释放完毕。