12.轻量级锁原理及其实战
文章目录
- 轻量级锁原理及其实战
- 1.轻量级锁的核心原理
- 2.轻量级锁的演示
- 2.1.轻量级锁的演示代码
- 2.2.结果分析
- 3.轻量级锁的分类
- 3.1.普通自旋锁
- 3.2.自适应自旋锁
- 4.轻量级锁的膨胀
轻量级锁原理及其实战
引入轻量级锁的主要目的是在多线程环境竞争不激烈的情况下, 通过CAS机制竞争锁减少重量级锁的产生的性能损耗,重量级锁使用了操作系统底层的互斥锁,会导致线程在用户态和核心态之间频繁切换,从而带来较大的性能损耗
1.轻量级锁的核心原理
轻量级锁存在目的就是尽可能的不去动用操作系统层面的互斥锁,因为性能较差。其实很多对象的锁的状态只会持续很短的一段时间,例如整数的自增运算,CPU很快就执行完毕了,在短时间内阻塞和唤醒线程这样显得值得,为此JDK引入的轻量级锁
轻量级锁其实就是一种自旋锁
,因为JVM本身就是一种应用,所以希望在应用层面上通过自旋来解决这一类问题。
轻量级锁的执行过程,首先在 抢占锁线程进入临界区之前,如果内置锁没有被锁定,JVM首先在抢占锁线程中建立一个锁记录(Lock Record),用于存储对象目前的Mark Work拷贝
抢占锁线程首先处理好栈帧中的轻量级锁记录,然后通过CAS自旋,尝试将内置锁对象头的Mark Word 的 ptr_to_lock_record(锁记录指针),更新为抢占锁线程栈帧中锁记录的地址,如果这个更新执行成功了,这个线程就拥有了这个对象
然后JVM将Mark Word中lock的标志位改为 00(轻量级锁标志)
Mark Word的值被CAS更新后,包含锁对象信息的旧值就会被返回,这个时候需要抢占锁的线程找一个地方将旧 的Mark Word暂存起来。
锁记录是线程私有的,每个线程都有自己的一份锁记录,在创建完锁记录后,会将内置对象的MarkWord拷贝到锁记录的Displaced Mark Word字段,为什么这么做呢?
因为内置锁对象的Mark Word的结构会有所变化,Mark Word将会出现一个指向锁记录的指针,而不再存在无锁状态下的锁的哈希码等信息,所以必须将这些信息暂存起来,供后面锁释放的时候使用。
2.轻量级锁的演示
2.1.轻量级锁的演示代码
package com.hrfan.java_se_base.base.thread.jol;import com.hrfan.java_se_base.common.utils.SleepUtil;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.concurrent.CountDownLatch;/*** 轻量级锁演示*/
public class InnerLockTest {private static final Logger log = LoggerFactory.getLogger(InnerLockTest.class);@Test@DisplayName("测试轻量级锁的案例")public void test() {// 打印JVM信息log.error("JVM参数信息:{}", VM.current().details());SleepUtil.sleepMillis(5000);LightweightObjectLock lock = new LightweightObjectLock();// 打印抢占锁前 锁状态log.error("抢占锁前,lock状态");lock.printLockStatus();SleepUtil.sleepMillis(5000);CountDownLatch latch = new CountDownLatch(2);Runnable runnable = () -> {for (int i = 0; i < 1000; i++) {synchronized (lock){lock.increase();if (i == 1){log.error("第一个线程占有锁,lock状态!");lock.printLockStatus();}}}// 第一个线程执行完毕latch.countDown();// 线程虽然释放锁,但是一致存在死循环while (true){// 每次循环等待1msSleepUtil.sleepMillis(1);}};new Thread(runnable).start();// 等待1sSleepUtil.sleepMillis(1000);Runnable lightweightRunnable = () -> {for (int i = 0; i < 1000; i++) {synchronized (lock){lock.increase();if (i == 500){log.error("第二个线程占有锁,lock状态!");lock.printLockStatus();}// 每次循环等待1msSleepUtil.sleepMillis(1);}}// 循环执行完毕latch.countDown();};new Thread(lightweightRunnable).start();// 等待全部线程执行完毕try {latch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}SleepUtil.sleepMillis(2000);log.error("释放锁后,lock状态!");lock.printLockStatus();}
}
class LightweightObjectLock{private static final Logger log = LoggerFactory.getLogger(MyObjectLock.class);private int count = 0;/*** 打印当前对象的一个状态*/public void printLockStatus(){log.error(ClassLayout.parseInstance(this).toPrintable());}/*** 将当前共享变量自增*/public void increase(){this.count++;}
}
2.2.结果分析
3.轻量级锁的分类
轻量级锁主要有两种,普通自旋锁 和 自适应自旋锁
3.1.普通自旋锁
普通自旋锁,就是指当有线程来竞争时,抢占锁线程就会在原地循环等待,而不是阻塞,直到那个占有线程释放锁之后,这个抢占线程才可以获得锁。
默认情况下 自旋的次数为10次,可以通过 -XX:PreBlockSpin选项来进行修改
自旋锁的主要优势在于避免了线程的上下文切换和阻塞唤醒的开销,这对于一些锁竞争非常激烈但持有锁的时间很短的情况下,可以提升性能。然而,在锁竞争激烈且持有锁时间较长的情况下,自旋锁可能会导致资源的浪费和性能下降。
自旋锁的实现机制可以简单描述如下:
- 当线程尝试获取锁时,如果发现锁已被其他线程占用,则进入自旋等待状态,不断地检查锁是否被释放。
- 自旋等待通常是通过使用一个循环来实现的,循环中会不断地检查锁的状态。这里需要注意的是,自旋等待时需要使用一种合适的方式来避免过度消耗CPU资源,例如可以在循环中添加一些延迟操作或者进行自适应自旋等待。
- 当持有锁的线程释放锁时,其他线程中的一个线程会成功获取到锁,并继续执行下去。
需要注意的是,在使用自旋锁时需要考虑一些问题:
- 自旋等待时间的设定:自旋等待时间过长会导致CPU资源的浪费,自旋等待时间过短则可能增加锁竞争的概率。合理设定自旋等待时间可以根据具体应用场景和硬件环境进行调整。
- 自适应自旋等待:一些现代的锁实现中采用了自适应自旋等待的策略,根据锁竞争的情况动态调整自旋等待时间,以提高性能。
- 超过自旋次数后的处理:如果一个线程在自旋等待一定次数后仍然无法获取到锁,可以选择进入阻塞状态,避免资源的浪费。这种策略被称为自旋锁的退化机制。
3.2.自适应自旋锁
自适应自旋锁,就是等待空循环的自旋次数并非是固定的,而是动态的根据实际情况来改变自旋的次数,自旋的次数由前一次在同一个锁上的自旋的时间以及锁的拥有着状态来决定,主要分为两种情况
- 如果抢占线程在同一个锁对象上之前成功获得过锁,那么JVM就会认为i这次自旋也很有可能再次成功,因此允许自旋等待持续相对较长
- 如果对于某个锁,抢占线程很少成功获得过,那么JVM将可能减少自旋等待时间甚至忽略自旋等待过程,以避免浪费处理器资源
- JDK1.7后,轻量级锁使用的就是自适应自旋锁,JVM自动开启,且自旋时间由JVM自动控制
- 轻量级锁也被称为 非阻塞同步、乐观锁,因为过程并没有吧线程阻塞挂起,而是线程空循环等待!
自适应自旋锁是一种改进的自旋锁实现方式,其根据前一次在同一个锁上的自旋时间以及锁的拥有者状态来动态调整自旋等待的次数。它的目标是在不同的锁竞争情况下,优化自旋等待的效果,减少资源的浪费。
具体实现自适应自旋锁的方式可能会因不同的JVM实现而有所差异,但其大致原理可以描述如下:
- 初始自旋次数:当一个线程第一次尝试获取锁时,JVM会给予一个初始的自旋次数。
- 自旋等待与锁竞争:线程在自旋等待期间持续尝试获取锁。如果线程在自旋等待期间成功获得了锁,那么JVM会根据前一次的自旋等待时间以及锁的拥有者状态来判断是否增加自旋次数。
- 自旋次数调整:根据前一次的自旋等待时间和锁的拥有者状态,JVM可能会逐渐增加或减少自旋等待的次数。如果前一次的自旋等待时间较长,表明自旋等待有效,JVM可能会增加自旋次数。如果前一次的自旋等待时间较短,表明自旋等待效果不佳,JVM可能会减少自旋次数或者直接放弃自旋等待。
- 自旋等待的退化:如果经过一定次数的自旋等待后仍然无法获得锁,JVM可能会将自旋等待退化为阻塞等待,避免资源的浪费。
自适应自旋锁的优势在于根据实际情况动态调整自旋等待的次数,可以在不同的锁竞争情况下提供更好的性能。通过根据前一次自旋等待时间和锁的拥有者状态进行自适应调整,可以更有效地利用处理器资源。然而,自适应自旋锁的具体实现可能会因JVM的不同版本和配置而有所差异,因此在具体应用中仍需考虑实际情况和性能需求来选择合适的锁实现方式。
4.轻量级锁的膨胀
轻量级锁膨胀是指在使用轻量级锁的过程中,如果锁竞争激烈或者存在其他特定情况,JVM会将轻量级锁膨胀为重量级锁。这种膨胀操作的目的是为了更好地处理锁竞争情况,确保多线程的安全性。
下面是轻量级锁膨胀的一般过程:
- 初始状态:当一个线程尝试获取轻量级锁时,JVM会先检查该对象是否被锁定。如果该对象未被锁定,JVM会将该对象的锁记录信息设置为指向当前线程的线程ID,并将对象头部的标记位设置为轻量级锁标记。
- 锁竞争:如果有另一个线程也尝试获取同一个对象的锁。在轻量级锁的设计中,如果锁竞争不激烈,JVM会使用自旋等待的方式,让竞争线程在自旋过程中等待锁的释放。
- 轻量级锁膨胀:如果锁竞争激烈或者其他特定情况发生,JVM会将轻量级锁膨胀为重量级锁。膨胀的过程包括以下步骤:
- 锁记录的升级:JVM会将之前记录在对象头部的锁记录信息替换为指向重量级锁的指针。这个指针指向一个互斥量(如操作系统原生的互斥量)来实现线程的阻塞和唤醒。
- 线程阻塞:竞争锁的线程会被阻塞,进入到等待队列中,等待锁的释放。
- 线程唤醒:当持有锁的线程释放锁时,JVM会将等待队列中的一个线程唤醒,使其获取锁并继续执行。
膨胀为重量级锁的过程会引入较大的性能开销,因为需要进行线程的阻塞和唤醒操作。然而,当锁竞争激烈时,使用重量级锁可以更好地处理多线程并发访问的安全性问题。
相关文章:
12.轻量级锁原理及其实战
文章目录 轻量级锁原理及其实战1.轻量级锁的核心原理2.轻量级锁的演示2.1.轻量级锁的演示代码2.2.结果分析 3.轻量级锁的分类3.1.普通自旋锁3.2.自适应自旋锁 4.轻量级锁的膨胀 轻量级锁原理及其实战 引入轻量级锁的主要目的是在多线程环境竞争不激烈的情况下, 通过…...
栈结构(c语言)
1.栈的概念 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。 压栈&am…...
【C++】C/C++中新const用法:const成员
欢迎来到CILMY23的博客 本篇主题为: C/C中新const用法:const成员 个人主页:CILMY23-CSDN博客 系列专栏:Python | C | C语言 | 数据结构与算法 | 贪心算法 | Linux 感谢观看,支持的可以给个一键三连,点赞…...
武汉凯迪正大—钢管焊缝裂纹探伤仪
产品概述 武汉凯迪正大无损探伤仪是一种便携式工业无损探伤仪器, 能够快速便捷、无损伤、精确地进行工件内部多种缺陷(裂纹、夹杂、气孔等)的检测、定位、评估和诊断。既可以用于实验室,也可以用于工程现场。 设置简单,…...
为什么 IP 地址通常以 192.168 开头?
在网络配置中,我们经常会遇到以 192.168 开头的 IP 地址,例如 192.168.0.1 或者 192.168.1.100。 这些地址通常用于局域网中,但为什么要选择以 192.168 开头呢? 本文将深入探讨这个问题,并解释其背后的原因和历史渊源…...
elementUi中的el-table合计行添加点击事件
elementUi 文档中,合计行并没有点击事件,这里自己实现了合计行的点击事件。 created() {this.propertyList [{ property: order, label: 序号 },{ property: deptName, label: 单位名称 },{ property: contentPublishQuantity, label: 文章数量 },{ pro…...
Zookeeper集群搭建的一些问题
问题描述一: Cannot open channel to 2 at election address /192.168.60.132:3888解决方案: 查看zookeeper配置文件zoo.cfg / zoo_sample.cfg中集群配置部分 server.1zoo1-net1:2888:3888|zoo1-net2:2889:3889 server.2zoo2-net1:2888:3888|zoo2-net2…...
【线性代数】俗说矩阵听课笔记
基础解系的概念 线性方程组的解 21行列式和矩阵秩Rank的等价刻画 子式 标准型 利用子式求解矩阵的rank 24零积秩不等式 齐次线性方程组的基础解系 rank的两个重要结论 ¥25伴随矩阵的rank 奇异矩阵:行列式0的矩阵 31线性相关,线性无关&#…...
物联网技术在数字化工厂中的应用,你知道多少?——青创智通
工业物联网解决方案-工业IOT-青创智通 物联网(IoT)技术在数字化工厂的应用正日益成为工业革命的重要推动力。随着科技的飞速发展,物联网技术不断革新,其在数字化工厂中的应用也呈现出愈发广泛和深入的态势。本文将详细探讨物联网…...
nacos开启登录开关启动报错“Unable to start embedded Tomcat”
nacos 版本:2.3.2 2.2.2版本之前的Nacos默认控制台,无论服务端是否开启鉴权,都会存在一个登录页;在之后的版本关闭了默认登录页面,无需登录直接进入控制台操作。在这里我们可以在官网可以看到相关介绍 而我现在所用的…...
Linux|了解如何使用 awk 内置变量
引言 当我们揭开 Awk 功能部分时,我们将介绍 Awk 中内置变量的概念。您可以在 Awk 中使用两种类型的变量:用户定义的变量和内置变量。 内置变量的值已经在 Awk 中定义,但我们也可以仔细更改这些值,内置变量包括: FILEN…...
代码随想录-算法训练营day29【回溯算法05:递增子序列、全排列】
代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 第七章 回溯算法part05* 491.递增子序列 * 46.全排列 * 47.全排列 II详细布置 491.递增子序列 本题和大家刚做过的 90.子集II 非常像,但又很不一样,很容易掉坑里。 https://programmercarl.com…...
704. 二分查找
Problem: 704. 二分查找 🐷我的leetcode主页 文章目录 题目分类思路什么是二分查找如何理解时间复杂度 解题方法Code 题目 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target&a…...
php回车变br、php显示br
在 PHP 中,如果你想将回车符(\n)转换为 HTML 的 <br> 标签来实现换行显示,可以使用内置函数 nl2br()。这个函数会将文本中的换行符替换为 <br> 标签。以下是使用 nl2br() 函数的示例代码: <?php $tex…...
找最大数字-第12届蓝桥杯国赛Python真题解析
[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python蓝桥杯真题解析100讲》,这是解读系列的第60讲。 找最大数字&#…...
蓝桥杯 算法提高 ADV-1170 阶乘测试 python AC
找规律题,遍历i中有几个m就加几,和m的多少次数有关 第一版👇 try:while True:n, m map(int, input().split())ll [i for i in range(1, n 1) if i % m 0]ans len(ll)M mwhile ll:lll []M * mfor i in ll:if i % M 0:lll.append(i)a…...
阿里巴巴杭州全球总部正式启用,创新“减碳大脑”科技减碳 | 最新快讯
来源:封面新闻 封面新闻记者付文超 5 月 10 日,记者获悉,位于未来科技城的阿里巴巴杭州全球总部新园区正式启用,这是阿里巴巴目前最大的综合性办公园区。从空中俯瞰,园区正中央呈现阿里标志性的笑脸 logo,这…...
蓝桥杯国赛练习题真题Java(矩阵计数)
题目描述 一个 NM 的方格矩阵,每一个方格中包含一个字符 O 或者字符 X。 要求矩阵中不存在连续一行 3 个 X 或者连续一列 3 个 X。 问这样的矩阵一共有多少种? 输入描述 输入一行包含两个整数 N,M (1≤N,M≤5)。 输出描述 输出一个整数代表答案。…...
概念解析 | ROC曲线:评估分类模型
注1:本文系"概念解析"系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:ROC曲线的含义和绘制 概念解析 | ROC曲线:评估分类模型 第一部分:通俗解释 在我们的日常生活中,经常会遇到需要做出判断和选择的情况。比如,当你收到一封邮件时…...
数据可视化训练第二天(对比Python与numpy中的ndarray的效率并且可视化表示)
绪论 千里之行始于足下;继续坚持 1.对比Python和numpy的性能 使用魔法指令%timeit进行对比 需求: 实现两个数组的加法数组 A 是 0 到 N-1 数字的平方数组 B 是 0 到 N-1 数字的立方 import numpy as np def numpy_sum(text_num):"""…...
【Java EE】数据库连接池详解
文章目录 🎍数据库连接池🌸Hikari🌸Druid 🍀MySQL开发企业规范⭕总结 🎍数据库连接池 在上⾯Mybatis的讲解中,我们使⽤了数据库连接池技术,避免频繁的创建连接,销毁连接 下⾯我们来了解下数据库连接池 数据库连接池负…...
正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-15.4讲 GPIO中断实验-IRQ中断服务函数详解
前言: 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…...
如何平衡RPA机器人的安全性与业务敏捷性,同时不牺牲用户体验?
平衡RPA机器人的安全性与业务敏捷性,同时不牺牲用户体验,是RPA实施中的一个关键挑战。以下是一些策略和最佳实践: ### 1. 安全设计原则 从设计阶段就将安全性纳入考虑,遵循安全设计原则。这意味着在开发RPA解决方案时࿰…...
地球行星UE5和UE4
地球行星,包含多种地球风格,可蓝图控制自转和停止,可材质自转. 支持版本4.21-5.4版本 下载位置:https://mbd.pub/o/bread/ZpWZm5lv b站工坊:https://gf.bilibili.com/item/detail/1105582041 _______________________…...
7.k8s中的名称空间namespace
目录 一、Namespace(命名空间) 二、查看系统的名称空间 1.查看系统中的名称空间列表 2.单独查看一个名称空间下的对应资源 三、名称空间的管理 1.创建名称空间 1.1响应式创建 1.2声明式创建 2.删除名称空间 四、资源引用名称空间 一、Namespace(命名空间) 命名空间(Name…...
上海企业源代码防泄密解决方案,企业源代码防泄密如何应对?
随之互联网的发展,企业员工因离职把企业源代码泄露或删库跑路的事情屡见不鲜,各大互联网公司基本都会出现源代码泄露的事情,这样的问题也成了企业在发展过程中不可避免的问题。企业源代码泄露会给企业带来的损失也是不可估量的,据…...
将要上市的自动驾驶新书《自动驾驶系统开发》中摘录各章片段 4
第十三章 车联网 数字化设备正变得越来越普遍并且相互联系。这些设备向数字生态系统智能部分的演进创造了迄今为止尚未解决安全问题的新颖应用。一个特定的例子是车辆,随着车辆从简单的交通方式发展到具有新的感知和通讯功能的智能实体,就成为智能城市的…...
OpenSearch 与 Elasticsearch:7 个主要差异及如何选择
OpenSearch 与 Elasticsearch:7 个主要差异及如何选择 1. 什么是 Elasticsearch? Elasticsearch 是一个基于 Apache Lucene 构建的开源、RESTful、分布式搜索和分析引擎。它旨在处理大量数据,使其成为日志和事件数据管理的流行选择。 Elasti…...
[Docker]容器的网络类型以及云计算
目录 知识梗概 1、常用命令2 2、容器的网络类型 3、云计算 4、云计算服务的几种主要模式 知识梗概 1、常用命令2 上一篇已经学了一些常用的命令,这里补充两个: 导出镜像文件:[rootdocker ~]# docker save -o nginx.tar nginx:laster 导…...
VMP 简单源码分析(.net)
虚拟机 获取CPU的型号 实现了一个指令集解释器,每个操作码对应一个特定的处理函数,用于执行相应的指令操作。在执行字节码时,解释器会根据操作码查找并调用相应的处理函数来执行指令。 截获异常 先由虚拟机处理 处理不了再抛出异常 priva…...
如何做网站跳转页面/长春网站建设模板
Echarts是一款声明式的可视化图表库,相比于其他图表库,其主要的优势在于易用性、内置丰富的交互以及高性能。本文在Echarts5发布之际,笔者重新学习echarts,主要结合18年Echarts的一篇文章,来对Echarts有一个更深入的了…...
如何给网站添加音乐/seo技术分享博客
对一个dynamic工程,一般都是手动添加服务器,然后进行开发。有时候也可以利用eclipse的tomcat插件,使用起来还是挺方便的,只是配置的时候需要注意一些项目的配置,否则tomcat插件找不见运行时需要的classes文件等&#x…...
做淘客网站需要企业的域名/百度关键词规划师入口
如今,电子书轻便海量的良好移动式体验受到广大年轻读者的喜爱。但是很多人也发现,有些电子书网站很贵,某些书籍还搜不到。今天,就给大家推荐6个电子书网站,不仅免费,而且品类丰富,能帮你找到99%…...
网站建设百度云/北京网上推广
算法设计与分析 钻石金字塔问题 一、 问题描述 现在你的任务是从金字塔的顶端向金字塔的底端收集钻石,并且尽可能收集价值高的钻石,但是只能从一块砖斜向左下或斜向右下走到另一块砖上,如从上图从用红色 A 标记的砖走向用蓝色 B 标记的砖上。…...
地产网站建设方案/网址查询工具
编译原理_哈尔滨工业大学_中国大学MOOC(慕课)...
wordpress上传视频大小/站长工具怎么用
一、概述在正常细胞中,磷脂酰丝氨酸只分布在细胞膜脂质双层的内侧,细胞发生凋亡最早期,膜磷脂酰丝氨酸(PS)由脂膜内侧翻向外侧,这一变化早于细胞皱缩、染色质浓缩、DNA片断化和细胞膜的通透性增加等凋亡现象。AnnexinV是一种磷脂结…...