Java中的锁[原理、锁优化、CAS、AQS]

Java~并发编程CAS和AQS原理刨析,东软java面试题 if (!} else { 阅读详情

 2020年最新的常问企业面试题大全以及答案

作者:高广超
链接:https://www.jianshu.com/p/e674ee68fd3f

1、为什么要用锁?

锁-是为了解决并发操作引起的脏读、数据不一致的问题。

2、锁实现的基本原理

2.1、volatile

★

Java编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。

volatile在多处理器开发中保证了共享变量的“ 可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。

”

image.png

结论:如果volatile变量修饰符使用恰当的话,它比synchronized的使用和执行成本更低,因为它不会引起线程上下文的切换和调度。

2.2、synchronized

★

synchronized通过锁机制实现同步。

”

先来看下利用synchronized实现同步的基础:Java中的每一个对象都可以作为锁。

具体表现为以下3种形式。

  • 对于普通同步方法,锁是当前实例对象。

  • 对于静态同步方法,锁是当前类的Class对象。

  • 对于同步方法块,锁是Synchonized括号里配置的对象。

当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。

2.2.1 synchronized实现原理

★

synchronized是基于Monitor来实现同步的。

”

Monitor从两个方面来支持线程之间的同步:

  • 互斥执行

  • 协作

1、Java 使用对象锁 ( 使用 synchronized 获得对象锁 ) 保证工作在共享的数据集上的线程互斥执行。

2、使用 notify/notifyAll/wait 方法来协同不同线程之间的工作。

3、Class和Object都关联了一个Monitor。

Monitor 的工作机理

  • 线程进入同步方法中。

  • 为了继续执行临界区代码,线程必须获取 Monitor 锁。如果获取锁成功,将成为该监视者对象的拥有者。任一时刻内,监视者对象只属于一个活动线程(The Owner)

  • 拥有监视者对象的线程可以调用 wait() 进入等待集合(Wait Set),同时释放监视锁,进入等待状态。

  • 其他线程调用 notify() / notifyAll() 接口唤醒等待集合中的线程,这些等待的线程需要重新获取监视锁后才能执行 wait() 之后的代码。

  • 同步方法执行完毕了,线程退出临界区,并释放监视锁。

参考文档:https://www.ibm.com/developerworks/cn/java/j-lo-synchronized

2.2.2 synchronized具体实现

1、同步代码块采用monitorenter、monitorexit指令显式的实现。

2、同步方法则使用ACC_SYNCHRONIZED标记符隐式的实现。

通过实例来看看具体实现:

public class SynchronizedTest {

    public synchronized void method1(){
        System.out.println("Hello World!");
    }

    public  void method2(){
        synchronized (this){
            System.out.println("Hello World!");
        }
    }
}

javap编译后的字节码如下:

image.png

monitorenter

每一个对象都有一个monitor,一个monitor只能被一个线程拥有。当一个线程执行到monitorenter指令时会尝试获取相应对象的monitor,获取规则如下:

  • 如果monitor的进入数为0,则该线程可以进入monitor,并将monitor进入数设置为1,该线程即为monitor的拥有者。

  • 如果当前线程已经拥有该monitor,只是重新进入,则进入monitor的进入数加1,所以synchronized关键字实现的锁是可重入的锁。

  • 如果monitor已被其他线程拥有,则当前线程进入阻塞状态,直到monitor的进入数为0,再重新尝试获取monitor。

monitorexit

只有拥有相应对象的monitor的线程才能执行monitorexit指令。每执行一次该指令monitor进入数减1,当进入数为0时当前线程释放monitor,此时其他阻塞的线程将可以尝试获取该monitor。

2.2.3 锁存放的位置

锁标记存放在Java对象头的Mark Word中。

Java对象头长度

32位JVM Mark Word 结构

32位JVM Mark Word 状态变化

64位JVM Mark Word 结构

2.2.3 synchronized的锁优化

JavaSE1.6为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”。

在JavaSE1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。

锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。

偏向锁:
★

无锁竞争的情况下为了减少锁竞争的资源开销,引入偏向锁。

”

image.png

轻量级锁:
★

轻量级锁所适应的场景是线程交替执行同步块的情况。

”

image.png

**锁粗化(Lock Coarsening):**也就是减少不必要的紧连在一起的unlock,lock操作,将多个连续的锁扩展成一个范围更大的锁。

**锁消除(Lock Elimination):**锁削除是指虚拟机即时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行削除。

**适应性自旋(Adaptive Spinning):**自适应意味着自旋的时间不再固定了,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也很有可能再次成功,进而它将允许自旋等待持续相对更长的时间,比如100个循环。另一方面,如果对于某个锁,自旋很少成功获得过,那在以后要获取这个锁时将可能省略掉自旋过程,以避免浪费处理器资源。

2.2.4 锁的优缺点对比

image.png

2.3、CAS

★

CAS,在Java并发应用中通常指CompareAndSwap或CompareAndSet,即比较并交换。

”

1、CAS是一个原子操作,它比较一个内存位置的值并且只有相等时修改这个内存位置的值为新的值,保证了新的值总是基于最新的信息计算的,如果有其他线程在这期间修改了这个值则CAS失败。CAS返回是否成功或者内存位置原来的值用于判断是否CAS成功。

2、JVM中的CAS操作是利用了处理器提供的CMPXCHG指令实现的。

优点:

  • 竞争不大的时候系统开销小。

缺点:

  • 循环时间长开销大。

  • ABA问题。

  • 只能保证一个共享变量的原子操作。

3、Java中的锁实现

3.1、队列同步器(AQS)

★

队列同步器AbstractQueuedSynchronizer(以下简称同步器),是用来构建锁或者其他同步组件的基础框架。

”

3.1.1、它使用了一个int成员变量表示同步状态。

image.png

3.1.2、通过内置的FIFO双向队列来完成获取锁线程的排队工作。

  • 同步器包含两个节点类型的应用,一个指向头节点,一个指向尾节点,未获取到锁的线程会创建节点线程安全(compareAndSetTail)的加入队列尾部。同步队列遵循FIFO,首节点是获取同步状态成功的节点。

    image.png

  • 未获取到锁的线程将创建一个节点,设置到尾节点。如下图所示:

image.png

  • 首节点的线程在释放锁时,将会唤醒后继节点。而后继节点将会在获取锁成功时将自己设置为首节点。如下图所示:

    image.png

3.1.3、独占式/共享式锁获取

★

独占式:有且只有一个线程能获取到锁,如:ReentrantLock。

共享式:可以多个线程同时获取到锁,如:CountDownLatch

”
独占式
  • 每个节点自旋观察自己的前一节点是不是Header节点,如果是,就去尝试获取锁。

    image.png

  • 独占式锁获取流程:

image.png

共享式:
  • 共享式与独占式的区别:

    image.png

  • 共享锁获取流程:

image.png

4、锁的使用用例

4.1、ConcurrentHashMap的实现原理及使用

ConcurrentHashMap类图

ConcurrentHashMap数据结构

结论:ConcurrentHashMap使用的锁分段技术。首先将数据分成一段一段地存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。

(完)

推荐阅读:

如何在面试中介绍自己的项目经验?

SpringBoot实现过滤器、拦截器与切片

Git 从入门到精通,这篇包教包会!

2020 年 9 大顶级 Java 框架

130 个相见恨晚的超实用网站,一次性分享出来

好文!必须点赞
Java外置锁实现原理 Java中的锁,如,ReentrantLock(显式锁)、CountDownLatch(闭锁)等都是基于AQS(队列同步器)来实现的,AQS又是CLH队列锁的一种变体实现。下面对这些锁的知识进行详细介绍。 阅读详情

相关推荐

Telegram 担保交易系统搭建指南:安全可靠的交易流程实现

本文介绍了基于Telegram Bot API搭建担保交易系统的完整方案。该系统通过第三方资金托管机制解决买卖双方信任问题,支持"付款后发货"和"收货后放款"的交易流程。文章详细阐述了系统架构设计,包括Telegram Bot交互层、后端业务逻辑层、数据库层和支付接口层。核心实现步骤涵盖:1)订单创建模块处理交易信息;2)支付处理模块集成Stripe Escrow实现资金托管;3)确认收货模块完成资金划转。系统采用PostgreSQL存储交易数据,并通过FastAPI

jingpide9527的博客 1960

java cas 和AQS

什么是CAS机制 CAS是英文单词Compare And Swap的缩写,翻译过来就是比较并替换。 CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。 更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。 CAS是英文单词Compare And Swap的缩写,翻译过来就是比较并替换。 CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。 更新一个变量的时候,只有当变量的预期值A和内存地址

Meiko记录 1131

基于 openEuler 24.03 LTS 源码编译安装 Zabbix 7.4

Zabbix是一款开源的企业级分布式监控系统,支持网络、服务器、应用等多种IT资源的监控。核心功能包括数据采集、告警通知、可视化展示等,采用Server/Agent架构,支持多种操作系统。本文详细介绍了在openEuler 24.03系统上部署Zabbix 7.4.2的完整流程,包括环境准备、MySQL配置、PHP/Apache安装、Zabbix编译安装等步骤,为构建企业级监控系统提供了实践指导。

广然笔记 1193

【Java并发编程】AQS和CAS

AQS和CAS

weixin_44735928的博客 1722

高速接口电平标准互连设计:LVPECL、PECL与LVDS的实战解析

本文深入解析了LVPECL、PECL与LVDS三种高速接口电平标准的互连设计实战。针对信号共模电压、阻抗匹配等核心差异,详细对比了直流耦合与交流耦合两种主流方案,并提供了电阻网络计算、布局布线要点及光模块等特殊场景下的选型建议,帮助工程师解决高速信号间的“翻译”难题,确保信号完整性。

weixin_29198045的博客 542

保姆级教程:用CellOracle 0.10.13分析你的单细胞数据,从GRN构建到基因扰动模拟

本文详细介绍了如何使用CellOracle 0.10.13进行单细胞数据分析,从基因调控网络(GRN)构建到基因扰动模拟的全流程。通过环境配置、数据准备、GRN构建和扰动模拟等步骤,帮助研究者高效预测细胞命运决定的分子机制,特别针对实际分析中的易错点提供解决方案。

weixin_42525005的博客 439

Java中的锁原理、锁优化、CAS、AQS详解

无锁、偏向锁、轻量级锁、重量级锁,这四种锁状态分别代表什么,为什么会有锁升级?其实在 JDK 1.6之前,synchronized 还是一个重量级锁,是一个效率比较低下的锁,但是在JDK 1.6后,Jvm为了提高锁的获取与释放效率对()进行了优化,引入了偏向锁 和 轻量级锁,从此以后锁的状态就有了四种(无锁、偏向锁、轻量级锁、重量级锁),并且四种状态会随着竞争的情况逐渐升级,而且是不可逆的过程,即不可降级,也就是说只能进行锁升级(从低级别到高级别),不能锁降级(高级别到低级别)

tanksyg的专栏 1098

M1/M2 Mac用户看过来:不装VirtualBox,用PD虚拟机也能跑ENSP的保姆级教程

本文为M1/M2 Mac用户提供了一份不依赖VirtualBox,使用Parallels Desktop虚拟机运行ENSP的详细指南。通过ARM架构的Win10镜像选择、组件替代方案和网络配置优化,实现ENSP核心功能的高效运行,特别适合网络工程师在苹果芯片设备上进行网络模拟。

weixin_28683065的博客 413

Java中的锁原理、锁优化、CAS、AQS

一、为什么要用锁? 锁-是为了解决并发操作引起的脏读、数据不一致的问题。 二、锁实现的基本原理 2.1、volatile Java编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。 volatile在多处理器开发中保证了共享变量的“ 可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。 image 结论:如果volatile变量修饰符

weixin_50666791的博客 562

什么是 AIDV(AI 定义汽车):从软件定义到智能决策的范式革命

AI定义汽车(AIDV),是指以人工智能(尤其是大模型、深度学习、强化学习)为核心引擎,以车载AI芯片为算力底座,以“数据闭环”为迭代支撑,重构汽车感知、决策、执行全链路,实现“感知智能化、决策自主化、体验个性化、迭代自动化”的新一代智能汽车发展范式。其核心是让汽车从“执行工具”升级为“具备自主学习与智能决策能力的移动智能终端”,核心价值是“车与人的深度协同”与“复杂场景的自主适配”。

getusushu的博客 97

【第1章>第9节】基于FPGA的图像开运算处理算法的Verilog实现

本文介绍了基于FPGA的开运算图像处理实现方法。主要内容包括:1)输入图像二值化处理,通过阈值将灰度图像转换为二值图像;2)数据缓存与窗口提取,使用寄存器数组缓存5行图像数据并构建5×5处理窗口;3)腐蚀运算逻辑,判断窗口内是否全为白色像素;4)膨胀运算逻辑,检测窗口内是否存在白色像素。最后给出了Verilog实现方案,通过级联腐蚀和膨胀模块完成开运算处理。该方法可用于FPGA图像处理算法开发。

MATLAB,verilog,python,opencv,tensorflow,caffe,C,C++ 315

Java中的锁原理、锁优化、CAS、AQS详解!

目录 一、为什么要用锁? 二、锁实现的基本原理 2.1、volatile 2.2、synchronized 2.2.1 synchronized实现原理 2.2.2 synchronized具体实现 2.2.3 锁存放的位置 2.2.3 synchronized的锁优化 2.2.4 锁的优缺点对比 2.3、CAS 三、Java中的锁实现 3.1、队列同步器(AQS) 3....

凡是过往,皆为序章 489

华为 MetaERP 集成盘古大模型、天筹 AI 求解器等生成式 AI 相关技术能力,结合华为云数智融合平台的支撑,在供应链预测中围绕需求预测、物料匹配

华为 MetaERP 集成盘古大模型、天筹 AI 求解器等生成式 AI 相关技术能力,结合华为云数智融合平台的支撑,在供应链预测中围绕需求预测、物料匹配、风险预警等核心场景开展实践,大幅提升了供应链预测的精准度与效率,以下是具体实践内容及成效: 动态需求预测,降低库存偏差华为供应链涉及数万种采购物料,物料清单层级高,且市场需求波动大。MetaERP 集成华为云 ModelArts 等工具构建专属动态需求预测模型,融合深度学习算法,纳入市场趋势、历史销售、产能数据等多维度信息进行综合预测。在华为自身供应链应

金牌架构师 701

Java 中的锁原理、锁优化、CAS、AQS 详解!

来源:jianshu.com/p/e674ee68fd3f1、为什么要用锁?锁-是为了解决并发操作引起的脏读、数据不一致的问题。2、锁实现的基本原理2.1、volatil...

Java团长的博客 167

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

深入介绍Java中的锁[原理、锁优化、CAS、AQS]

1、为什么要用锁? 锁-是为了解决并发操作引起的脏读、数据不一致的问题。 2、锁实现的基本原理 2.1、volatile Java编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。 volatile在多处理器开发中保证了共享变量的“ 可见性”。可见性的意思是当一个...

u011679955的博客 163

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

一文看懂Java中的CAS、AQS、锁原理、锁优化

编辑:业余草来源:https://www.xttblog.com/?p=49181、为什么要用锁?锁-是为了解决并发操作引起的脏读、数据不一致的问题。2...

xmt1139057136的专栏 933

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

java锁的实现原理_深入介绍Java中的锁[原理、锁优化、CAS、AQS]

1、为什么要用锁?锁-是为了解决并发操作引起的脏读、数据不一致的问题。2、锁实现的基本原理2.1、volatileJava编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。volatile在多处理器开发中保证了共享变量的“ 可见性”。可见性的意思是当一个线程修改一个共享变量时...

weixin_32619013的博客 801

带你深入了解Java中的锁(原理、锁优化、CAS、AQS)

带你深入了解Java中的锁(原理、锁优化、CAS、AQS) 1、为什么要用锁? 锁-是为了解决并发操作引起的脏读、数据不一致的问题。 2、锁实现的基本原理 2.1、volatile Java编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。 volatile在多处理器开发中...

qq_26598941的博客 197

Java中的锁原理、锁优化、CAS、AQS,看这篇就对了!

01 为什么要用锁? 锁-是为了解决并发操作引起的脏读、数据不一致的问题。 02锁实现的基本原理 2.1、volatileJava编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。volatile在多处理器开发中保证了共享变量的“ 可见性”。可见性的意思是...

田维常 572

java cas原理_深入介绍Java中的锁(原理、锁优化、CAS、AQS)

1、为什么要用锁?锁-是为了解决并发操作引起的脏读、数据不一致的问题。2、锁实现的基本原理2.1、volatileJava编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言提供了volatile,在某些情况下比锁要更加方便。volatile在多处理器开发中保证了共享变量的“ 可见性”。可见性的意思是当一个线程修改一个共享变量时...

weixin_39966644的博客 114
上一篇: 程序员 6 个接私活的网站,你有技术就有钱!
下一篇: Spring的Bean生命周期,11 张高清流程图及代码,深度解析
Java思维导图
博客等级 码龄10年 306粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值