Java并发编程Synchronized

346 阅读17分钟
原文链接: mp.weixin.qq.com
点击上方“蓝字”关注我们

Synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法。

Synchronized三个作用

1、确保线程互斥的访问同步代码。

2、保证共享变量的修改能够及时可见。

3、有效解决重排序问题。

Synchronized是一把重量级的锁。何为重量级的锁?就是申请资源的时候必须通过系统内核需要通过系统调用(可以了解下用户态和内核态),就是需要通过用户态向内核态进行调用。不经过内核的锁都可以称之为用户空间的锁,是轻量级的锁。

一、Synchronized原理

1、Java源码层级

package com.test.concurrent;public class synchronizedTest {    public void method() {        synchronized (this) {            System.out.println("synchronized method");        }    }}

2、java字节码(monitorenter moniterexit)

public class com.test.concurrent.synchronizedTest {  public com.test.concurrent.synchronizedTest();    Code:       0: aload_0       1: invokespecial #1                  // Method java/lang/Object."<init>":()V       4: return  public void method();    Code:       0: aload_0       1: dup       2: astore_1       3: monitorenter       4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;       7: ldc           #3                  // String synchronized method       9: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V      12: aload_1      13: monitorexit      14: goto          22      17: astore_2      18: aload_1      19: monitorexit      20: aload_2      21: athrow      22: return    Exception table:       from    to  target type           4    14    17   any          17    20    17   any}

我们参考下JVM对monitorenter和moniterexit的解释:

monitorenter :

The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner.Other threads that are blocking to enter the monitor are allowed to attempt to do so.

moniterexit

The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.

但是我们会发现方法的同步并没有通过指令monitorenter和monitorexit来完成(理论上其实也可以通过这两条指令来实现),不过相对于普通方法,其常量池中多了ACC_SYNCHRONIZED标示符。JVM就是根据该标示符来实现方法的同步的:当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。其实本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成。如下图:

public com.test.concurrent.SynchronizedTest1();    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 9: 0      LocalVariableTable:        Start  Length  Slot  Name   Signature            0       5     0  this   Lcom/test/concurrent/SynchronizedTest1;  public synchronized void method();    descriptor: ()V    flags: ACC_PUBLIC, ACC_SYNCHRONIZED    Code:      stack=2, locals=1, args_size=1         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;         3: ldc           #3                  // String synchronized method         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V         8: return      LineNumberTable:        line 12: 0        line 13: 8      LocalVariableTable:        Start  Length  Slot  Name   Signature            0       9     0  this   Lcom/test/concurrent/SynchronizedTest1;

3、JVM层级(HotSpot)

先看下对象在内存中的存储布局

MarkWord:用于存储对象自身的运行时数据。

class point:对象指向它的类型元数据指针,Java虚拟机通过这个指针来确定该对象是哪个类的实例。

instance data:对象真正存储的有效信息,即我们在程序代码里面所定义的各种类型的字段内容。

padding:起着占位符的作用,如果其他部分不能被8整除就补齐到被8整除,或者这样说任何对象的大小必须是8字节的整数倍,因为JVM是按块来读取数据的。

那么是如何对对象进行上锁的呢?先来看个普通对象

public class ObjectTest {    public static void main(String[] args) {        Object object = new Object();        String s = ClassLayout.parseInstance(object).toPrintable();        System.out.println(s);    }}
"C:\Program Files\Java\jdk1.8.0_241\bin\java.exe" "-javaagent:E:\Program Files\JetBrains\IntelliJ IDEA 2018.3.6\lib\idea_rt.jar=64379:E:\Program Files\JetBrains\IntelliJ IDEA 2018.3.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_241\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\rt.jar;E:\yubs\ideaWorkspace\leaf_share_tools\target\classes;E:\yubs\apache-maven-3.2.2\repository\com\alibaba\fastjson\1.2.62\fastjson-1.2.62.jar;E:\yubs\apache-maven-3.2.2\repository\commons-lang\commons-lang\2.1\commons-lang-2.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\apache\zookeeper\zookeeper\3.4.8\zookeeper-3.4.8.jar;E:\yubs\apache-maven-3.2.2\repository\org\slf4j\slf4j-api\1.6.1\slf4j-api-1.6.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\slf4j\slf4j-log4j12\1.6.1\slf4j-log4j12-1.6.1.jar;E:\yubs\apache-maven-3.2.2\repository\log4j\log4j\1.2.16\log4j-1.2.16.jar;E:\yubs\apache-maven-3.2.2\repository\jline\jline\0.9.94\jline-0.9.94.jar;E:\yubs\apache-maven-3.2.2\repository\io\netty\netty\3.7.0.Final\netty-3.7.0.Final.jar;E:\yubs\apache-maven-3.2.2\repository\org\apache\curator\curator-recipes\2.11.1\curator-recipes-2.11.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\apache\curator\curator-framework\2.11.1\curator-framework-2.11.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\apache\curator\curator-client\2.11.1\curator-client-2.11.1.jar;E:\yubs\apache-maven-3.2.2\repository\com\google\guava\guava\16.0.1\guava-16.0.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-context\4.3.9.RELEASE\spring-context-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-beans\4.3.9.RELEASE\spring-beans-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-core\4.3.9.RELEASE\spring-core-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-expression\4.3.9.RELEASE\spring-expression-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-orm\4.3.9.RELEASE\spring-orm-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-oxm\4.3.9.RELEASE\spring-oxm-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-jdbc\4.3.9.RELEASE\spring-jdbc-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-tx\4.3.9.RELEASE\spring-tx-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-web\4.3.9.RELEASE\spring-web-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-webmvc\4.3.9.RELEASE\spring-webmvc-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-aop\4.3.9.RELEASE\spring-aop-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-test\4.3.9.RELEASE\spring-test-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.4\jackson-databind-2.9.4.jar;E:\yubs\apache-maven-3.2.2\repository\com\fasterxml\jackson\core\jackson-annotations\2.9.0\jackson-annotations-2.9.0.jar;E:\yubs\apache-maven-3.2.2\repository\com\fasterxml\jackson\core\jackson-core\2.9.4\jackson-core-2.9.4.jar;E:\yubs\apache-maven-3.2.2\repository\org\aspectj\aspectjweaver\1.8.13\aspectjweaver-1.8.13.jar;E:\yubs\apache-maven-3.2.2\repository\org\openjdk\jol\jol-core\0.9\jol-core-0.9.jar" com.test.concurrent.ObjectTestjava.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total

上图第4行和第5行总共8个字节(64位)代表的是Markword

上图第6行4个字节代表的是classpoint

上图第7行4个字节是为了补齐到16个字节

如果对object这个对象上个锁,那么内存的布局会发生什么变化呢?

public class ObjectTest {    public static void main(String[] args) {        Object object = new Object();        String s = ClassLayout.parseInstance(object).toPrintable();        System.out.println(s);        System.out.println("---synchronized分割线--");        synchronized (object) {            s = ClassLayout.parseInstance(object).toPrintable();            System.out.println(s);        }    }}
java.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total---synchronized分割线--java.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           10 f3 e1 02 (00010000 11110011 11100001 00000010) (48362256)      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total

从上图可以看出,给对象上锁实际上就是修改了对象头中的Markword的值,锁信息是写在了markWork上面的。

二、锁升级过程

从第一部分我们已经知道了锁信息是存在Markword上面的,那么锁升级只需要修改markWord的值,下图为64位Markwork实现表

上图可以看出,锁的状态有无锁、偏向锁、轻量级锁(自旋锁)、重量级锁。

那么升级流程是怎么样的呢?如下图:

偏向锁:顾名思义,它会偏向于第一个访问锁的线程,如果在运行过程中,同步锁只有一个线程访问,不存在多线程竞争用的情况,则线程是不需要触发同步的,这种情况下,就会给线程加一个偏向锁。(不会惊动操作系统)

自旋锁:持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。( 不会惊动操作系统)

重量级锁:其他线程试图获取锁时,都会被阻塞,只有持有锁的线程释放锁之后才会唤醒这些线程,进行竞争。

如果有线程上锁上偏向锁,指的就是,把markword的线程ID改为自己线程ID的过程。偏向锁不可重偏向 批量偏向 批量撤销

如果有线程竞争,撤销偏向锁,升级轻量级锁,线程在自己的线程栈生成LockRecord ,用CAS操作将markword设置为指向自己这个线程的LR的指针,设置成功者得到锁

竞争加剧:jdk1.6之前,有线程超过10次自旋,-XX:PreBlockSpin, 或者自旋线程数超过CPU核数的一半,jdk 1.6之后,加入自适应自旋 Adapative Self Spinning ,JVM自己控制升级重量级锁:向操作系统申请资源,linux mutex,CPU从3级-0级系统调用,线程挂起,进入等待队列,等待操作系统的调度,然后再映射回用户空间

最后看个例子代码如下

public class ObjectTest1 {    public static void main(String[] args) throws Exception {        Object object = new Object();        System.out.println("对象加锁之前");        System.out.println(ClassLayout.parseInstance(object).toPrintable());        synchronized (object) {            System.out.println("对象加锁之前中");            System.out.println(ClassLayout.parseInstance(object).toPrintable());        }        System.out.println("对象加锁之后");        System.out.println(ClassLayout.parseInstance(object).toPrintable());    }}
"C:\Program Files\Java\jdk1.8.0_241\bin\java.exe" "-javaagent:E:\Program Files\JetBrains\IntelliJ IDEA 2018.3.6\lib\idea_rt.jar=49844:E:\Program Files\JetBrains\IntelliJ IDEA 2018.3.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_241\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\rt.jar;E:\yubs\ideaWorkspace\leaf_share_tools\target\classes;E:\yubs\apache-maven-3.2.2\repository\com\alibaba\fastjson\1.2.62\fastjson-1.2.62.jar;E:\yubs\apache-maven-3.2.2\repository\commons-lang\commons-lang\2.1\commons-lang-2.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\apache\zookeeper\zookeeper\3.4.8\zookeeper-3.4.8.jar;E:\yubs\apache-maven-3.2.2\repository\org\slf4j\slf4j-api\1.6.1\slf4j-api-1.6.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\slf4j\slf4j-log4j12\1.6.1\slf4j-log4j12-1.6.1.jar;E:\yubs\apache-maven-3.2.2\repository\log4j\log4j\1.2.16\log4j-1.2.16.jar;E:\yubs\apache-maven-3.2.2\repository\jline\jline\0.9.94\jline-0.9.94.jar;E:\yubs\apache-maven-3.2.2\repository\io\netty\netty\3.7.0.Final\netty-3.7.0.Final.jar;E:\yubs\apache-maven-3.2.2\repository\org\apache\curator\curator-recipes\2.11.1\curator-recipes-2.11.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\apache\curator\curator-framework\2.11.1\curator-framework-2.11.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\apache\curator\curator-client\2.11.1\curator-client-2.11.1.jar;E:\yubs\apache-maven-3.2.2\repository\com\google\guava\guava\16.0.1\guava-16.0.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-context\4.3.9.RELEASE\spring-context-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-beans\4.3.9.RELEASE\spring-beans-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-core\4.3.9.RELEASE\spring-core-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-expression\4.3.9.RELEASE\spring-expression-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-orm\4.3.9.RELEASE\spring-orm-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-oxm\4.3.9.RELEASE\spring-oxm-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-jdbc\4.3.9.RELEASE\spring-jdbc-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-tx\4.3.9.RELEASE\spring-tx-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-web\4.3.9.RELEASE\spring-web-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-webmvc\4.3.9.RELEASE\spring-webmvc-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-aop\4.3.9.RELEASE\spring-aop-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-test\4.3.9.RELEASE\spring-test-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.4\jackson-databind-2.9.4.jar;E:\yubs\apache-maven-3.2.2\repository\com\fasterxml\jackson\core\jackson-annotations\2.9.0\jackson-annotations-2.9.0.jar;E:\yubs\apache-maven-3.2.2\repository\com\fasterxml\jackson\core\jackson-core\2.9.4\jackson-core-2.9.4.jar;E:\yubs\apache-maven-3.2.2\repository\org\aspectj\aspectjweaver\1.8.13\aspectjweaver-1.8.13.jar;E:\yubs\apache-maven-3.2.2\repository\org\openjdk\jol\jol-core\0.9\jol-core-0.9.jar" com.test.concurrent.ObjectTest1对象加锁之前java.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total对象加锁之前中java.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           d8 f5 93 02 (11011000 11110101 10010011 00000010) (43251160)      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total对象加锁之后java.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total

上面执行的代码没有资源竞争都是main线程在执行,在Jdk1.6之前,JVM中synchronized关键字的实现方式是调用操作系统底层的pthread_mutex_t函数实现加锁,而Jdk1.6之后进行了优化在没有资源竞争的情况下,JVM的加锁应该是偏向锁,但是从结果中看,肯定不是偏向锁,因为偏向标识是0,这里的000是一个轻量锁。

那么在执行以下代码

public class ObjectTest {    /**     * jvm参数:-XX:BiasedLockingStartupDelay=0     * */    public static void main(String[] args) throws  Exception{        Thread.sleep(5000);        Object object = new Object();        System.out.println("对象加锁之前");        System.out.println(ClassLayout.parseInstance(object).toPrintable());        synchronized (object) {            System.out.println("对象加锁之前中");            System.out.println(ClassLayout.parseInstance(object).toPrintable());        }        System.out.println("对象加锁之后");        System.out.println(ClassLayout.parseInstance(object).toPrintable());    }}
"C:\Program Files\Java\jdk1.8.0_241\bin\java.exe" -XX:BiasedLockingStartupDelay=0 "-javaagent:E:\Program Files\JetBrains\IntelliJ IDEA 2018.3.6\lib\idea_rt.jar=50023:E:\Program Files\JetBrains\IntelliJ IDEA 2018.3.6\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_241\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_241\jre\lib\rt.jar;E:\yubs\ideaWorkspace\leaf_share_tools\target\classes;E:\yubs\apache-maven-3.2.2\repository\com\alibaba\fastjson\1.2.62\fastjson-1.2.62.jar;E:\yubs\apache-maven-3.2.2\repository\commons-lang\commons-lang\2.1\commons-lang-2.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\apache\zookeeper\zookeeper\3.4.8\zookeeper-3.4.8.jar;E:\yubs\apache-maven-3.2.2\repository\org\slf4j\slf4j-api\1.6.1\slf4j-api-1.6.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\slf4j\slf4j-log4j12\1.6.1\slf4j-log4j12-1.6.1.jar;E:\yubs\apache-maven-3.2.2\repository\log4j\log4j\1.2.16\log4j-1.2.16.jar;E:\yubs\apache-maven-3.2.2\repository\jline\jline\0.9.94\jline-0.9.94.jar;E:\yubs\apache-maven-3.2.2\repository\io\netty\netty\3.7.0.Final\netty-3.7.0.Final.jar;E:\yubs\apache-maven-3.2.2\repository\org\apache\curator\curator-recipes\2.11.1\curator-recipes-2.11.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\apache\curator\curator-framework\2.11.1\curator-framework-2.11.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\apache\curator\curator-client\2.11.1\curator-client-2.11.1.jar;E:\yubs\apache-maven-3.2.2\repository\com\google\guava\guava\16.0.1\guava-16.0.1.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-context\4.3.9.RELEASE\spring-context-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-beans\4.3.9.RELEASE\spring-beans-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-core\4.3.9.RELEASE\spring-core-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-expression\4.3.9.RELEASE\spring-expression-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-orm\4.3.9.RELEASE\spring-orm-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-oxm\4.3.9.RELEASE\spring-oxm-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-jdbc\4.3.9.RELEASE\spring-jdbc-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-tx\4.3.9.RELEASE\spring-tx-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-web\4.3.9.RELEASE\spring-web-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-webmvc\4.3.9.RELEASE\spring-webmvc-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-aop\4.3.9.RELEASE\spring-aop-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\org\springframework\spring-test\4.3.9.RELEASE\spring-test-4.3.9.RELEASE.jar;E:\yubs\apache-maven-3.2.2\repository\com\fasterxml\jackson\core\jackson-databind\2.9.4\jackson-databind-2.9.4.jar;E:\yubs\apache-maven-3.2.2\repository\com\fasterxml\jackson\core\jackson-annotations\2.9.0\jackson-annotations-2.9.0.jar;E:\yubs\apache-maven-3.2.2\repository\com\fasterxml\jackson\core\jackson-core\2.9.4\jackson-core-2.9.4.jar;E:\yubs\apache-maven-3.2.2\repository\org\aspectj\aspectjweaver\1.8.13\aspectjweaver-1.8.13.jar;E:\yubs\apache-maven-3.2.2\repository\org\openjdk\jol\jol-core\0.9\jol-core-0.9.jar" com.test.concurrent.ObjectTest对象加锁之前java.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total对象加锁之前中java.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           05 48 2b 03 (00000101 01001000 00101011 00000011) (53168133)      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total对象加锁之后java.lang.Object object internals: OFFSET  SIZE   TYPE DESCRIPTION                               VALUE      0     4        (object header)                           05 48 2b 03 (00000101 01001000 00101011 00000011) (53168133)      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)     12     4        (loss due to the next object alignment)Instance size: 16 bytesSpace losses: 0 bytes internal + 4 bytes external = 4 bytes total

结果为101 的确为偏向锁

-XX:BiasedLockingStartupDelay=0 就是这个参数的原因,这个参数是禁止偏向锁延迟,因为JVM默认是延迟开启偏向锁的,时间是4秒,那JVM为什么要延迟开启偏向锁呢?那是因为在JVM启动的时候JVM认为在JVM启动的时候,JVM的运行程序中的同步代码都是存在资源竞争的,没有必要开启偏向锁,JVM启动完了在开启偏向锁供用户使用。

扫码关注更多精彩 欢迎将文章分享到朋友圈 如需转载,请在后台回复“转载”获取授权 你点的每个赞,我都认真当成了喜欢