synchronized的实现原理

Java的每个对象都可以作为锁

表现为3种形式:

  • 对于普通方法,锁是当前实例。
  • 对于静态方法,锁是当前类的Class对象。
  • 对于同步方法,锁是synchronized括号里配置的对象。

JVM基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不一样。
代码块同步是使用monitorenter和monitorexit指令实现的,而方法同步是使用另外一种实现,细节在JVM规范里没有详细说明。
我们来看一下方法同步和代码块同步的字节码形式:

代码块同步

源码:

public class TestSynchronized {
    private final static Object MUTEX = new Object();

    public static void main(String[] args) {
        synchronized (MUTEX) {
            System.out.println("1");
        }
    }
}

对应字节码:

// class version 52.0 (52)
// access flags 0x21
public class bfxx/TestSynchronized {

  // compiled from: TestSynchronized.java

  // access flags 0x1A
  private final static Ljava/lang/Object; MUTEX

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 7 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lbfxx/TestSynchronized; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x9
  public static main([Ljava/lang/String;)V
    TRYCATCHBLOCK L0 L1 L2 null
    TRYCATCHBLOCK L2 L3 L2 null
   L4
    LINENUMBER 11 L4
    GETSTATIC bfxx/TestSynchronized.MUTEX : Ljava/lang/Object;
    DUP
    ASTORE 1
    MONITORENTER
   L0
    LINENUMBER 12 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "1"
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L5
    LINENUMBER 13 L5
    ALOAD 1
    MONITOREXIT
   L1
    GOTO L6
   L2
   FRAME FULL [[Ljava/lang/String; java/lang/Object] [java/lang/Throwable]
    ASTORE 2
    ALOAD 1
    MONITOREXIT
   L3
    ALOAD 2
    ATHROW
   L6
    LINENUMBER 14 L6
   FRAME CHOP 1
    RETURN
   L7
    LOCALVARIABLE args [Ljava/lang/String; L4 L7 0
    MAXSTACK = 2
    MAXLOCALS = 3

  // access flags 0x8
  static <clinit>()V
   L0
    LINENUMBER 8 L0
    NEW java/lang/Object
    DUP
    INVOKESPECIAL java/lang/Object.<init> ()V
    PUTSTATIC bfxx/TestSynchronized.MUTEX : Ljava/lang/Object;
    RETURN
    MAXSTACK = 2
    MAXLOCALS = 0
}

可以看到在LINENUMBER 12前面有MONITORENTER指令,在后面有MONITOREXIT指令。

方法同步

源码:

public class TestSynchronized {
    public static synchronized void test() {
        System.out.println("1");
    }
}

字节码:

// class version 52.0 (52)
// access flags 0x21
public class bfxx/TestSynchronized {

  // compiled from: TestSynchronized.java

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 7 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lbfxx/TestSynchronized; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x29
  public static synchronized test()V
   L0
    LINENUMBER 9 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "1"
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L1
    LINENUMBER 10 L1
    RETURN
    MAXSTACK = 2
    MAXLOCALS = 0
}

从字节码没有看到如何实现的进入和退出Monitor对象。

待补充:

  • monitor对象是什么?在哪里?
  • Java对象头
  • 锁升级
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值