聊一聊Synchronized锁的本质

232 阅读2分钟

在并发编程中,Java提供了关键字Synchronized作为一种内置锁机制来支持原子性,使用Synchronize语义的同步代码块包括两个部分组成:一个作为锁的对象引用,一个作为由这个锁保护的代码块。

synchronized (lock){
    //...
}

编写一个简单的Synchronized测试代码

public class SyncPrintTest {

    private static final Object lock = new Object();

    public  void print()  {
        synchronized (lock){
            System.out.println("Hello Synchronize!");
        }
    }
}

class文件编译后,使用javap -c SyncPrintTest查看字节码 可以看到由synchronized修饰的代码块,在代码块前后分别插入monitorenter和monitorexit指令。

  public com.yupaopao.test.SyncPrintTest();
    Code:
       0: aload_0
       1: invokespecial #1                  
       4: return

  public void print();
    Code:
       0: getstatic     #2
       3: dup
       4: astore_1
       5: monitorenter                      //这里是synchronized获取锁的字节码
       6: getstatic     #3                  
       9: ldc           #4                  
      11: invokevirtual #5                 
      14: aload_1
      15: monitorexit
      16: goto          24
      19: astore_2
      20: aload_1
      21: monitorexit                      //这里是synchronized释放锁的字节码
      22: aload_2
      23: athrow
      24: return
    Exception table:
       from    to  target type
           6    16    19   any
          19    22    19   any

  static {};
    Code:
       0: new           #6                  
       3: dup
       4: invokespecial #1                 
       7: putstatic     #2                  
      10: return
}

MarkWord

Synchronized是基于对象的锁,每个对象的脑袋上都顶着一个叫MarWord的东东,看看这个MarWord长啥样

通过一段测试代码来看一下对象头信息

public class SynchronizedTest {
    private static Object lock = new Object();

    public static void main(String[] args) {

        System.out.println(ClassLayout.parseInstance(lock).toPrintable());

        synchronized (lock){
            System.out.println(ClassLayout.parseInstance(lock).toPrintable());
        }
    }
}

使用OpenJdk的工具类,输出对象头信息,在工程中的pom文件中增加maven坐标

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.8</version>
</dependency>

对象头输出结果 image.png

JVM默认4秒后开启偏向锁,可以在启动参数里设置-XX:BiasedLockingStartupDelay=0,重新执行后可以看到偏向锁

image.png

Synchronized在字节码中的体现

被Synchronized修饰的方法或代码块在JVM中到底是如何执行的?本文从JVM和操作系统来分析Synchronized底层原理。

既然Synchronized是Java的关键字,那么在编译后的字节码中可以看到Synchronized生成的字节码指令。 可以看到synchronized实现同步锁的机制是依靠插入的monitorenter和monitorexit指令,即锁监视器,那么这两个指令在JVM中又是如何执行的? 在HotSpot虚拟机中,monitorenter和monitorexit指令执行的的源码在InterpreterRuntime.cpp文件中

JVM执行monitorenter方法

image.png

Monitor介绍

未完待续...