字节码分析-同步

源码

package java.bytecode;

/**
 * 同步示例 - 演示synchronized方法
 */
public class SynchronizedExample {

    private int counter = 0;

    // synchronized实例方法
    public synchronized void synchronizedMethod() {
        counter++;
        System.out.println("synchronizedMethod(): counter = " + counter);
    }

    // synchronized静态方法
    public static synchronized void synchronizedStaticMethod() {
        System.out.println("synchronizedStaticMethod()");
    }

    // 同步代码块
    public void synchronizedBlock() {
        synchronized (this) {
            counter++;
            System.out.println("synchronizedBlock(): counter = " + counter);
        }
    }

    public int getCounter() {
        return counter;
    }
}

结构化反解析

Classfile /D:/zcp/github/yggdrasil/java/bytecode/SynchronizedExample.class
  ...
{
  public synchronized void synchronizedMethod();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: dup
         2: getfield      #7                  // Field counter:I
         5: iconst_1
         6: iadd
         7: putfield      #7                  // Field counter:I
        10: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
        ...
        38: return

  public static synchronized void synchronizedStaticMethod();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #41                 // String synchronizedStaticMethod()
         5: invokevirtual #35                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return

  public void synchronizedBlock();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=3, args_size=1
         0: aload_0
         1: dup
         2: astore_1
         3: monitorenter
         4: aload_0
         5: dup
         6: getfield      #7                  // Field counter:I
         9: iconst_1
        10: iadd
        11: putfield      #7                  // Field counter:I
        14: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
        ...
        42: aload_1
        43: monitorexit
        44: goto          52
        47: astore_2
        48: aload_1
        49: monitorexit
        50: aload_2
        51: athrow
        52: return
      Exception table:
         from    to  target type
             4    44    47   any
            47    50    47   any
}

详细说明

ACC_SYNCHRONIZED标志

同步方法使用ACC_SYNCHRONIZED标志:

public synchronized void synchronizedMethod();
  flags: ACC_PUBLIC, ACC_SYNCHRONIZED

JVM会自动在方法调用时获取锁,方法返回时释放锁。

monitorenter/monitorexit

同步代码块使用monitorenter和monitorexit指令:

public void synchronizedBlock();
  Code:
     0: aload_0        // 加载this
     1: dup
     2: astore_1       // 存储到局部变量1
     3: monitorenter   // 获取锁
     4: ...            // 同步代码块
     42: aload_1
     43: monitorexit   // 释放锁
     44: goto          52
     47: astore_2      // 异常处理
     48: aload_1
     49: monitorexit   // 确保异常时也释放锁
     50: aload_2
     51: athrow
     52: return

异常处理

同步代码块需要确保在异常时也能释放锁,因此有多个monitorexit:

Exception table:
   from    to  target type
       4    44    47   any
      47    50    47   any

同步方法 vs 同步代码块

特性 同步方法 同步代码块
实现方式 ACC_SYNCHRONIZED标志 monitorenter/monitorexit
锁对象 实例方法:this
静态方法:Class对象
显式指定
性能 稍慢(JVM自动处理) 稍快(更细粒度控制)
灵活性 低 高

锁的获取和释放

可重入性

Java的synchronized是可重入的:同一个线程可以多次获取同一个锁。

性能考虑