Synchronized 锁升级过程

Posted lisin-lee-cooper

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Synchronized 锁升级过程相关的知识,希望对你有一定的参考价值。

一.Synchronized作用

修饰静态方法:锁住当前 class,作用于该 class 的所有实例
修饰非静态方法:只会锁住当前 class 的实例
修饰代码块:该方法接受一个对象作为参数,锁住的即该对象

二.Java对象结构

2.1对象头
mark Word:主要用于存储自身运行时数据,主要表示当前Java对象的线程锁状态(无锁,偏向锁,轻量级锁,重量级锁)以及GC的标志;
Class Pointer:是指针,指向方法区中该 class 的对象,JVM 通过此字段来判断当前对象是哪个类的实例;
数组长度:当且仅当对象是数组时才会有该字段;

2.2对象体:包含了当前对象的字段和值

2.3对其字节:用于填充的字节,其目的是为了保证对象所占用的内存大小为 8 的倍数

三.锁升级过程

3.1无锁
当线程运行,没有其他线程来竞争。锁的标志位为01

3.2 偏向锁
一直只被线程A访问,没有其他线程来竞争,标志位为01, biased_lock标志来区分,1 为启用偏向锁

3.3 轻量级锁
一旦有第二个线程参与竞争,立即膨胀为轻量级锁,企图抢占的线程一开始会使用自旋的方式尝试获取锁,1.7是普通自旋,设定一个最大的自旋次数,默认是10 ,1.7之后是自适应自旋,自旋获取到锁,则自旋的次数则会增加,自旋获取不到锁次数则会减少;

3.4 重量级锁
自旋达到阈值后无法获取到锁,则会膨胀为重量级锁,其他竞争的线程此时不会自旋而是直接阻塞等待,Mark Word中的内容会变成一个监视器对象,管理排队的线程。

monitor 对象本质上是一个同步机制,保证了同时只有一个线程能够进入临界区,在 HotSpot 的虚拟机中,是由 C++ 类 ObjectMonitor 实现的。

ObjectMonitor的属性:

ContentionQueue:是个队列,所有竞争锁的线程都会先进入这个队列中,可以理解为线程的统一入口,进入的线程会阻塞。
EntryList:ContentionQueue 中有资格的线程会被移动到这里,相当于进行一轮初筛,进入的线程会阻塞。
Owner:拥有当前 monitor 对象的线程,即 —— 持有锁的那个线程。
OnDeck:与 Owner 线程进行竞争的线程,同一时刻只会有一个 OnDeck 线程在竞争。
WaitSet:当 Owner 线程调用 wait() 方法被阻塞之后,会被放到这里。当其被唤醒之后,会重新进入 EntryList 当中,这个集合的线程都会阻塞。
Count:用于实现可重入锁,synchronized 是可重入的。

3.5锁升级过程

线程A进入synchronized开始抢锁,JVM判断当前是否是偏向锁状态,根据Mark Word中的owner 线程的Id来判断。如是是直接进入临界区内执行代码;

如果不是,则通过自旋尝试获取锁,如果获取到了则将Mark Word中的线程Id改为自己的,如果自旋失败,则膨胀为轻量级锁,自旋达到阈值还未成功则升级为重量级锁

后续的竞争线程通过自旋来尝试获取锁,自旋成功那么锁的状态仍然是轻量级锁,如果竞争失败,锁会膨胀为重量级锁,后续等待的线程都会被阻塞。

以上是关于Synchronized 锁升级过程的主要内容,如果未能解决你的问题,请参考以下文章

Synchronized锁升级过程 学习笔记

Synchronized锁升级过程 学习笔记

synchronized 锁升级过程

详细了解 Synchronized 锁升级过程

Java synchronized锁升级过程简述(面试可用)

synchronized 原理使用锁升级过程,写到我要吐血了