synchronize锁的几种情况

 一个java对象包含:对象头,数据,对齐填充;

对象头包含:markword(如上图),类类型指针(klass word,如上图),legth(若是数组对象有这个值)

现在讲解下上图:

上图是jvm64位的对象头在各种锁状态下的信息;正常情况markword占64bit ;klass word 占64bit(一般默认开启指针压缩的:会压缩到32bit)

要分析对象头我们可以借助jol:
 <dependency>
<groupId>org.openjdk.jol</groupId>
 <artifactId>jol‐core</artifactId>
 <version>0.9</version>
 </dependency>

public class A{}

public class JOLExample1 {
   public static void main(String[] args) throws Exception {
     out.println(VM.current().details());
     out.println(ClassLayout.parseClass(A.class).toPrintable());
   }
 }

这样子输出后的结果如下:

 # Running 64‐bit HotSpot VM.
 # Using compressed oop with 0‐bit shift.
# Using compressed klass with 3‐bit shift.
 # Objects are 8 bytes aligned.
 # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
 # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

 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) 82 22 01 20 (10000010 00100010 00000001 00100000) (536945282)
 12 4 (loss due to the next object alignment)
 Instance size: 16 bytes
 Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

可以看出来'' (object header)"总共12byte ,也就是96bit,所以这里的指针被压缩过了;

分析一下这个(markword)64bit的意思:

 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)

其中第一排括号里的前8bit表示: unsigned:0 ; age:0000 ; biased:0 ;lock:01

分别表示unsigned:没有使用,age:gc的分代年龄;biased:偏向锁的标志(0表示不是偏向锁,1表示是),lock:表示锁

这里的01表示无锁,00表示轻量锁,10表示重量锁;

下面这张图是32位的jvm:

synchronize锁的几种情况

64位的jvm和32的基本一致,后8位基本上是一样的,32位的时候无锁转态25bit表示hashcode值;

而64位是31bit表示hashcode值:如下图的括号里,从第一排第九个往下数31位表示hanscode值,剩下的25暂时没用到

 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)

jvm启动时默认会使用偏向锁延迟(jvm估计认为,用synchronize的情况大多数都有竞争),延迟开启差不多在4s时间,当然可以配置jvm参数:

启用参数: 
-XX:+UseBiasedLocking
关闭延迟: 
-XX:BiasedLockingStartupDelay=0 
禁用参数: 
-XX:-UseBiasedLocking

偏向锁怎么膨胀到轻量级锁或者到重量锁呢?

 首先偏向锁(如果一个对象调用了,hashcode()方法,该对象就不可以是偏向锁了)是资源有且只有一个线程在竞争;(偏向一个线程后,基本上后面都会膨胀锁,不会再偏向另一个线程(批量重偏向除外))

偏向锁->轻量锁:多个线程,且是交替的执行,也就是一个线程获取到锁后,执行完同步块,这时候,另一个线程还处在自旋转态

去获取锁,且获取到了,总的来说是交替获取锁

偏向锁->重量锁:偏向锁还没执行完同步块代码,另一个线程自旋获取该锁,一直没获取到,挂起线程,这时候锁会升级重量锁;

(对象调用了wait()方法,则肯定会升级重量锁)

偏向锁在执行完同步代码块,锁不会撤销成无锁的情况;

轻量锁和重量锁在执行完同步代码块后,会执行锁撤销操作(挺耗性能毕竟要跟内核交互),变成无锁情况

 

 

 

 

 

 

相关文章: