偏向锁,轻量级锁,重量级锁的核心原理

article/2025/10/21 13:06:18

前言:大家好,我是小威,24届毕业生,在一家满意的公司实习。本篇文章是关于并发编程中偏向锁,轻量级锁,重量级锁的核心原理知识记录。
本篇文章记录的基础知识,适合在学Java的小白,也适合复习中,面试中的大佬🤩🤩。
如果文章有什么需要改进的地方还请大佬不吝赐教👏👏。
小威在此先感谢各位大佬啦~~🤞🤞
在这里插入图片描述

🏠个人主页:小威要向诸佬学习呀
🧑个人简介:大家好,我是小威,一个想要与大家共同进步的男人😉😉
目前状况🎉:24届毕业生,在一家满意的公司实习👏👏

🎁如果大佬在准备面试,可以使用我找实习前用的刷题神器哦刷题神器点这里哟
💕欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,我亲爱的大佬😘

以下正文开始

在这里插入图片描述

文章目录

  • Java对象结构
    • 对象头
    • 实例数据
    • 对象填充
  • 偏向锁
  • 轻量级锁
  • 重量级锁
  • 锁升级
  • 锁消除

Java对象结构

在讲到本文的锁之前,先来简单了解一下Java的对象结构。Java的对象结构主要包括对象头,实例数据,对齐填充三大部分。
在这里插入图片描述

对象头

对象头中存储了对象的Mark word,类型指针(元数据指针)和数组长度(只有当前对象为数组对象时才会有)。而Mark word又包括对象的Hashcode码,对象的分代年龄,对象的偏向锁ID,获取偏向锁的时间戳,锁标志位等。

Mark word主要用于存储对象自身运行时的数据,并且Mark word字段的长度与JVM的位数有关,32位的JVM虚拟机中Mark word占用32位的存储空间,64位的JVM虚拟机中占用64位的储存空间

以32位的JVM虚拟机为例:
在这里插入图片描述

是否是偏向锁表示:当值为0时,标记对象没有开启偏向锁,值为1表示开启了偏向锁。

锁标志位表示:当前线程拥有的锁,不同状态下拥有的锁不同。

对象分代年龄表示:当JVM发生GC垃圾回收时,新生代未被回收的对象在Eden区和Survivor之间的复制,每次复制是的分代年龄+1,默认情况下分代年龄达到15会被移到老年代区域,当然这个参数也可以自行设置。

对象的Hashcode值:主要存储对象的Hashcode值。

线程ID:表示在偏向锁状态下,持有偏向锁的线程编号。

指向栈中锁记录的指针:在轻量级锁状态下,指向栈中所记录的指针。

指向(互斥量)重量级锁的指针:在重量级锁状态下,指向对象监视器的指针。

类型指针指向方法区中的类元信息,也叫元数据指针。

对于数组长度,在当前对象是数组类型的时候,对象头中需要额外的空间存储数据长度的信息,如果当前对象不是数组类型的,则不需要。同样,在32位的虚拟机中,数组长度占用32位的存储空间,64位的虚拟机中占用64位的存储空间。
在这里插入图片描述

实例数据

实例数据主要存储了对象的成员变量信息,比如成员变量的具体值,父类成员变量的具体值等。

对象填充

在HotSpot虚拟机中,对象的起始地址必须为8的整数倍,如果当前对象的实例变量占用的储存空间不是8的整数倍,则需要使用填充数据来保证对齐。

偏向锁

为什么会产生偏向锁?在多线程并发执行时,synchronized锁会保证安全性能,但是同时会出现一个线程多次获取同一个锁的现象(哎,就是玩😎),因此提出了偏向锁。

偏向锁是如何工作的?如果在同一时刻,只有一个线程拿到了synchronized锁,此时该线程执行方法或代码块不会出现与其他线程竞争的情况,这时,会进入偏向状态。当锁进入偏向状态,对象头中的Mark word就会进入偏向结构,由上文得知,偏向锁标记为1,锁标志位标记为01,并且会把当前拿到锁的线程ID记录到对象头的Mark word中,一旦下次改线程进入临界区(方法或代码块),那么会先检查Mark word中存储的ID和自己的是否一致。

如果发现Mark word中存储的线程ID和自己的一致,则可以进入临界区,如果不一致,说明有线程与当前拿到锁的线程竞争。假如线程1正在使用锁资源,线程2发现不一致,则线程2会尝试使用CAS机制将对象头Mark word中的线程ID改为线程2自己的,然而又会分为两种情况:

1.当CAS操作执行成功后,表示线程1已经结束了使用锁资源,Mark word中的线程ID会记录为线程2的ID,此时仍然处于偏向锁状态;

2.当CAS操作执行失败,表示线程1仍然在占用锁资源,没有释放锁资源,此时会暂停线程1,并且将Mark word中偏向锁的值设为0,锁标志位设为00,由上文可知,此时偏向锁会升级为轻量级锁,当然,线程1和线程2之间会按照轻量级锁的方式来竞争锁。

偏向锁会提升程序的执行性能,但是偏向锁的撤销升级是比较复杂的,并且会消耗资源和性能。
在这里插入图片描述

轻量级锁

轻量级锁概念是在线程竞争不是很激烈时,可以通过CAS机制来竞争锁,避免使用操作系统层面的Mutex重量级锁从而影响性能。

轻量级锁如何实现呢?当线程被创建后,虚拟机会在线程的栈帧中创建一个用于存储锁记录的空间–Displaced Mark word,对于轻量级锁,在争抢锁资源的线程进入synchronized修饰的方法或代码块之前,会将锁对象中对象头里的Mark word复制到当前线程的Displaced Mark word空间中,然后,线程会尝试使用CAS自旋的方式将锁对象中的Mark word替换成指向锁记录的指针,替换成功则代表当前线程拿到了锁,之后虚拟机会把Mark word中的锁标志位设为00,表示当前为轻量级锁状态,当前线程获取到锁之后,JVM虚拟机会把锁对象中Mark word中的信息保存到获取到的锁资源的线程的栈帧Displaced Mark word中,并且把线程中的owner指针指向锁对象。

当线程抢占到锁资源后,会将锁对象的Mark Word中的信息保存到当前线程栈帧中Displaced Mark World区域,而且锁对象的Mark Word信息也会发生变化,由之前的存储对象的HashCode码到现在变成存储指向栈中锁记录的指针。当线程释放锁时,会尝试使用CAS操作将Displaced Mark Word中存储的信息复制到锁对象中的Mark Word中,如果没有发生锁竞争,则代表复制成功,线程会释放锁,如果此时由于其他线程多次执行CAS操作导致轻量级锁升级为重量级锁,则当前线程的CAS操作会失败,此时会释放锁并唤醒其他未获得锁而被阻塞的线程同时竞争锁。
在这里插入图片描述

重量级锁

重量级锁主要基于操作系统中的Mutex锁实现的,重量级锁的执行效率比较低,处于重量级锁时被阻塞的线程不会消耗CPU资源。
它的底层是通过Monitor锁实现等待,如果当前对象锁的状态为偏向锁或轻量级锁,那么在调用锁对象的wait方法或notify方法,或者计算锁对象的HashCode时,偏向锁或轻量级锁就会膨胀为重量级锁。
在这里插入图片描述

锁升级

在多线程同时争抢锁时,可能会由无锁状态慢慢升级为轻量级锁,重量级锁的情况,升级过程如下:

在多线程竞争锁时,虚拟机会检测锁对象头中的Mark Word偏向锁标记是否为1,锁标记位是否为01,如果是的话,则当前锁状态为可偏向状态;

多线程争抢锁资源时,会首先检查Mark Word中存储的是不是自己线程的ID,如果是自己线程的话,则已经处于偏向锁状态了,当前的线程可以直接进入方法或代码块中;

如果存储的不是自己的线程,那么当前竞争锁的线程会使用CAS自旋机制来竞争锁,如果竞争成功,则会把Mark Word中存储的线程ID改为当前竞争锁成功的ID,并且把偏向锁标记设为1,锁标志位设为01,此时锁状态仍然处于偏向锁状态;如果当前线程通过CAS自旋操作竞争失败,则说明有其他线程也在争抢锁资源,那么此时会撤销偏向锁,将偏向锁升级为轻量级锁;

当前线程通知锁对象的Mark Word中存储的线程ID暂停线程,对应的线程会将Mark Word的内容变为空;

上次拿到偏向锁资源的线程(线程1),和当前争抢锁的线程(线程2)都会把锁对象中的HashCode值等信息复制到自己栈帧中的Displaced Mark Word中,之后线程1和线程2开始执行CAS自旋操作,尝试把锁对象中的Mark Word的内容修改为指向自己线程的Displaced Mark Word的空间来竞争锁资源;

竞争成功的线程会拿到锁资源,并且竞争成功的锁的线程会把锁对象中的Mark Word的内容修改为指向自己线程的Displaced Mark Word的空间,并将Mark Word中的锁标志为设为00,进入轻量级锁状态;

当时竞争失败的锁不会灰心的,仍然会继续CAS自旋的操作来竞争锁资源,此时又会分为两种情况:如果竞争成功,则会拿到轻量级锁,注意是轻量级,此时锁仍然会处于轻量级锁状态;如果竞争失败,线程一直进行CAS自旋操作达到一定的次数仍然没有拿到锁资源,那么轻量级锁会膨胀为重量级锁,将Mark Word中的锁标志位设置为10进入重量级锁状态。

因此,综上所述,当同一时刻,只有一个线程竞争锁时,此时会处于偏向锁状态;如果有多个线程同时竞争锁时,偏向锁会升级为轻量级锁状态;当线程以CAS自旋机制超过了一定的自旋次数,仍然没有获取到锁,会由轻量级锁升级为重量级锁状态。
在这里插入图片描述

锁消除

只有Java虚拟机开启了逃逸分析,才会出现锁消除的现象,意思是当一个对象只能从一个线程被访问到,不存在共享数据的竞争,在访问这个对象时,可以不加同步锁,如果使用了synchronized同步锁,则虚拟机会自动将synchronized同步锁消除,常见的例子有StringBuffer拼接字符串:

public static String add(String str1, String str2) {StringBuffer sb = new StringBuffer();sb.append(str1);sb.append(str2); return sb.toString();   }

StringBuffer中的append()方法源码:

    public synchronized StringBuffer append(StringBuffer sb) {toStringCache = null;super.append(sb);return this;}

上述代码中,总所周知StringBuffer是线程安全的,其方法被synchronized锁修饰,虽然存在锁,但是在执行上述代码时,其他线程无法访问到共享数据,因此虚拟机会将synchronized锁安全消除。
在这里插入图片描述

本篇文章就分享到这里了,后续将会分享各种其他关于并发编程的知识,感谢大佬认真读完支持咯 ~
在这里插入图片描述

文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起讨论🍻
希望能和诸佬们一起努力,今后进入到心仪的公司
再次感谢各位小伙伴儿们的支持🤞

在这里插入图片描述


http://chatgpt.dhexx.cn/article/9sITKQkn.shtml

相关文章

深入探究synchronize锁机制

synchronized 有三种方式来加锁,分别是: **1. 修饰实例方法:**作用于当前实例加锁,进入同步代码前要获得当前实例的锁 **2. 静态方法:**作用于当前类加锁,进入同步代码前要获得当前类的锁 **3. 修饰代码块&…

偏向锁的原理与实战

文章目录 1. 偏向锁的核心原理2. 偏向锁代码演示3. 偏向锁的膨胀与撤销 1. 偏向锁的核心原理 如果不存在线程竞争的一个线程获得了锁,那么锁就进入偏向状态,此时Mark Word的结构变为偏向锁结构,锁对象的锁标志位(lock)…

Java并发 | 19.[锁机制] 偏向锁(CAS)

文章目录 1. 偏向锁分析回顾轻量级锁偏向锁的优势 2. 偏向锁(CAS)2.1. 偏向锁流程概述2.2. 锁升级 参考资料 1. 偏向锁分析 回顾轻量级锁 在上文 Java并发 | 18.[锁机制] 轻量级锁(CAS自旋锁)中对轻量级锁进行过解析&#xff0c…

Synchronized-偏向锁

偏向锁是什么? 是jdk1.6引入的一种锁优化方式。让 锁对象 偏心于第一次获取锁的线程,记住它的id,当下一次再有线程获取锁的时候,与记录的ID匹配,直接获取锁就行。是一种load-and-test的过程。 引入目的? …

面试题-- 什么是偏向锁

所谓的偏向,就是偏心,即锁会偏向于当前已经占有锁的线程 。 大部分情况是没有竞争的(某个同步块大多数情况都不会出现多线程同时竞争锁),所以可以通过偏向来提高性能。即在无竞争时,之前获得锁的线程再次获…

Java中的偏向锁,轻量级锁, 重量级锁解析

文章目录 参考文章Java 中的锁一些先修知识synchronized 关键字之锁的升级(偏向锁->轻量级锁->重量级锁)无锁 -> 偏向锁偏向锁的撤销(Revoke)偏向锁的批量再偏向(Bulk Rebias)机制偏向锁 -> 轻…

条件分布

1.离散型: 例1: 2.连续型:

关于多元正态分布的条件分布的证明

之前在机器学习 cs229学习笔记3 (EM alogrithm,Mixture of Gaussians revisited & Factor analysis )中直接给出了多元正态分布的条件概率 正好今天上课讲了多元正态分布的内容,但没有涉及条件概率,所以下来baidu了一下,找到一个不错的pp…

条件分布函数(离散-条件分布律)

一、离散随机变量的条件分布函数 1.0、条件分布函数定义 1.1、例 1.1.1、例1 1.1.2、例2 二、连续型随机变量的条件分布函数 2.1、连续随机变量的条件分布函数 2.2、条件概率密度函数

第三章 多维随机变量及其分布 3.3 条件分布

第三章 多维随机变量及其分布 3.3 条件分布 文章目录 第三章 多维随机变量及其分布 3.3 条件分布离散型随机变量的条件分布连续型随机变量的条件分布 离散型随机变量的条件分布 例: 求: 离散型的直接套条件概率的公式就行了。 连续型随机变量的条件分布…

~《概率论》~条件分布

《概率论》条件分布 文章目录 ~《概率论》~条件分布一、离散型随机向量的条件分布1.1、定义1.2、性质 二、连续型随机向量的条件分布2.1、定义2.2、性质 一、离散型随机向量的条件分布 1.1、定义 1.2、性质 二、连续型随机向量的条件分布 2.1、定义 2.2、性质

MCMC算法--Gibbs采样2:多元高斯分布的边际分布与条件分布推导

因为在下篇博客中会介绍Gibbs采样,代码示例用到的是多元高斯分布,所以对条件分布,边际分布公式必须写出来,所以博主整理了下。 参考文献为:http://fourier.eng.hmc.edu/e161/lectures/gaussianprocess/node7.html 由…

条件高斯分布

多元高斯分布的一个重要性质是如果两个变量集是联合高斯分布,那么其中一个基于另一个变量集上的条件分布仍然是高斯分布。边缘高斯分布也有类似结论。 考虑第一种情形的条件高斯分布。假设 X 是一个满足高斯分布 的 D 维向量,我们把 X 分作两个子集 Xa 和…

【概率论】3-6:条件分布(Conditional Distributions Part I)

原文地址1:https://www.face2ai.com/Math-Probability-3-6-Conditional-Distributions-P1转载请标明出处 Abstract: 首先介绍随机变量的条件分布,随后介绍随机变量条件分布下的乘法法则,贝叶斯公式和全概率公式 Keywords: Discrete Conditio…

概率论与数理统计(3.3)二维随机变量条件分布

这个条件分布主要只针对二维的 一、离散型随机变量的条件分布 同理固定一个X为一个常数则可得Y的条件分布律 **注:**离散型的求在什么条件下X或Y的条件分布律,知道他们的联合分布律很重要. 1) 观察这个公式。 注:必须知道P{X1}的…

多元正态分布条件分布公式总结

假设X是有两个随机向量组成 其中 假设X服从多元高斯分布其中 多元正态分布

【概率论】二维随机变量:联合分布律、边缘分布律和条件分布律之间的关系

摘要:本文主要介绍二维随机变量的联合分布律、边缘分布律和条件分布律之间的关系,并以矿山事故为例,强化对三者关系的认识。 一、联合分布律、边缘分布律和条件分布律之间的关系 1、若已知(X, Y)的联合分布率 > 可以求出X的边缘分布律和…

用最简洁的方法证明多元正态分布的条件分布

在证明高斯-马尔科夫随机过程的性质的过程中,遇到了多元正态分布的条件分布的证明,百度发现条件分布的很多证明方法写的极其麻烦,所以自己写了一个。 实际上多元随机变量的公式证明一般用矩阵的方法处理,这里就是采用这种方法&…

联合分布、条件分布、边缘分布还有贝叶斯公式

https://blog.csdn.net/zgcr654321/article/details/85201614?utm_mediumdistribute.pc_relevant.none-task-blog-OPENSEARCH-1.nonecase&depth_1-utm_sourcedistribute.pc_relevant.none-task-blog-OPENSEARCH-1.nonecase 文章目录 联合概率及其分布、边缘概率及其分布、…