Java多线程编程核心技术(第3版)
上QQ阅读APP看书,第一时间看更新

2.1.3 同步synchronized在字节码指令中的原理

在方法上使用synchronized关键字实现同步的原因是使用了flag标记ACC_SYNCHRONIZED,当调用方法时,调用指令将会检查方法的ACC_SYNCHRONIZED访问标志是否设置,如果设置了,执行线程先持有同步锁,然后执行方法,最后在方法完成时释放锁。

测试代码如下:


public class Test {
synchronized public static void testMethod() {
}
public static void main(String[] args) throws InterruptedException {
    testMethod();
}
}

在cmd中使用命令javap来将class文件转成字节码指令,参数-v表示输出附加信息,参数-c表示对代码进行反汇编。

使用javap.exe命令如下:


javap -c -v Test.class

生成这个class文件对应的字节码指令,指令的核心代码如下:


public synchronized void myMethod();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
    stack=1, locals=2, args_size=1
        0: bipush        100
        2: istore_1
        3: return
    LineNumberTable:
        line 5: 0
        line 6: 3
    LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       4     0  this   Ltest56/Test;
            3       1     1   age   I

在反编译的字节码指令中对public synchronized void myMethod()方法使用了flag标记ACC_SYNCHRONIZED,说明此方法是同步的。

如果使用synchronized代码块,则使用monitorenter和monitorexit指令进行同步处理,测试代码如下:


public class Test2 {
public void myMethod() {
    synchronized (this) {
        int age = 100;
    }
}

public static void main(String[] args) throws InterruptedException {
    Test2 test = new Test2();
    test.myMethod();
}
}

在cmd中使用命令:


javap -c -v Test2.class

生成这个class文件对应的字节码指令,指令的核心代码如下:


public void myMethod();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
        stack=2, locals=3, args_size=1
            0: aload_0
            1: dup
            2: astore_1
            3: monitorenter
            4: bipush        100
            6: istore_2
            7: aload_1
            8: monitorexit
            9: goto          15
            12: aload_1
            13: monitorexit
            14: athrow
            15: return

由代码可知,在字节码中使用了monitorenter和monitorexit指令进行同步处理。