JVM原理(二三):JVM虚拟机线程安全的实现方法

1. 互斥同步

互斥同步(MutualExclusion&Synchronization)是一种最常见也是最主要的并发正确性保障手段。同步是指在多个线程并发访问共享数据时,保证共享数据在同一个时刻只被一条(或者是一些,当使用信号量的时候)线程使用而互斥是实现同步的一种手段,临界区(Critical Section)、互斥量(Mutex)和信号量( Semaphore)都是常见的互斥实现方式。因此在“互斥同步”这四个字里面,互斥是因,同步是果;互斥是方法,同步是目的。


其他名称:阻塞同步、悲观锁。面临的问题主要是进行线程阻塞和唤醒所带来的性能开销。


在Java里面,最基本的互斥同步手段就是synchronized关键字,这是一种块结构(Block Structured)的同步语法。

Synchronized内部结构

synchronized关键字经过Javac编译之后,会在同步块的前后分别形成monitorenter和monitorexit这两个字节码指令。这两个字节码指令都需要一个reference类型的参数来指明要锁定和解锁的对象。如果Java源码中的synchronized明确指定了对象参数,那就以这个对象的引用作为reference;如果没有明确指定,那将根据synchronized修饰的方法类型(如实例方法或类方法),来决定是取代码所在的对象实例还是取类型对应的Class对象来作为线程要持有的锁。

Synchronized原理和实现过程

根据《Java虚拟机规范》的要求,在执行monitorenter指 令时,首先要去尝试获取对象的锁。如果这个对象没被锁定,或者当前线程已经持有了那个对象的锁,就把锁的计数器的值增加一,而在执行monitorexit指令时会将锁计数器的值减一。一旦计数器的值为零,锁随即就被释放了。如果获取对象锁失败,那当前线程就应当被阻塞等待,直到请求锁定的对象被持有它的线程释放为止。

Synchronized注意点

  • 被synchronized修饰的同步块对同一条线程来说是可以重入的。这意味着同一线程反复进入同步块也不会出现自己把自己锁死的情况。

  • 被synchronized修饰的同步块在持有锁的线程执行完毕并释放锁之前,会无条件地阻塞后面其他线程的进入。这意味着无法像处理某些数据库中的锁那样,强制已获取锁的线程释放锁;也无法强制正在等待锁的线程中断等待或超时退出。

Synchronized执行成本

Synchronized是一个重量级的操作,有经验的程序员都只会在确实有必要的情况下才使用这种操作。虚拟机本身也会进行一些优化,比如在通知系统之前加入一段自选等待过程。


JDK5以后加入了LOCK,重入锁(ReentrantLock)是Lock接口一种常见的实现方式。

ReentrantLock相比Synchronized增加了一些高级功能,主要有以下三项:等待可中断、可实现公平锁以及所可以绑定多个条件。

等待可中断:是指当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情。可中断特性对处理执行时间非常长的同步块很有帮助。

公平锁:是指多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁;而非公平锁则不保证这一点,在锁被释放时,任何一个等待锁的线程都有机会获得锁。synchronized中的锁是非公平的,ReentrantLock在默认情况下也是非公平的,但可以通过带布尔值的构造函数要求使用公平锁。不过一旦使用了公平锁,将会导致ReentrantLock的性能急剧下降,会明显影响吞吐量。

锁绑定多个条件:是指一个ReentrantLock对象可以同时绑定多个Condition对象。在synchronized中,锁对象的wait()跟它的notify()或者notifyAll()方法配合可以实现一个隐含的条件,如果要和多于一个的条件关联的时候,就不得不额外添加一个锁;而ReentrantLock则无须这样做,多次调用newCondition()方法即可。


Synchronized和ReentrantLock的对比

如果Synchronized和ReentrantLock都满足的情况下,优先推荐使用Synchronized

  • synchronized是在Java语法层面的同步,足够清晰,也足够简单。每个Java程序员都熟悉synchronized,但J.U.C中 的Lock接口则并非如此。因此在只需要基础的同步功能时,更推荐synchronized。

  • Lock应该确保在finally块中释放锁,否则一旦受同步保护的代码块中抛出异常,则有可能永远不会释放持有的锁。这一-点必须由程序员自己来保证,而使用synchronized的话则可以由Java虛拟机来确保即使出现异常,锁也能被自动释放。

  • 尽管在JDK 5时代ReentrantLock曾经在性能上领先过synchronized,但这已经是十多年之前的胜利了。从长远来看,Java虛拟机更容易针对sy nchronized来进行优化,因为Java虚拟机可以在线程和对象的元数据中记录synchronized中锁的相关信息,而使用J.U.C中的Lock的话,Java虛 拟机是很难得知具体哪些锁对象是由特定线程锁持有的。

2. 非阻塞同步

非同步阻塞:就是不管风险,先进行操作,如果没有其他线程争用共享数据,那操作就直接成功了;如果共享的数据的确被争用,产生了冲突,那再进行其他的补偿措施,最常用的补偿措施是不断地重试,直到出现没有竞争的共享数据为止。


其他名词:乐观锁、无锁编程。


常见的乐观锁实现比如CAS(Java最终使用的也是这个),它的底层基于比较并交换(Compare-and-swap)指令。

CAS实现原理

CAS指令需要有三个操作数,分别是内存位置(在Java中可以简单地理解为变量的内存地址,用V表示)、旧的预期值(用A表示)和准备设置的新值(用B表示)。CAS指令执行时,当且仅当V符合A时,处理器才会用B更新V的值,否则它就不执行更新。但是,不管是否更新了V的值,都会返回V的旧值,上述的处理过程是一个原子操作,执行期间不会被其他线程中断。

CAS存在的问题

CAS从语义上来说并不是真正完美的,它存在一个逻辑漏洞:如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然为A值,那就能说明它的值没有被其他线程改变过了吗?这是不能的,因为如果在这段期间它的值曾经被改成B,后来又被改回为A,那CAS操作就会误认为它从来没有被改变过。这个漏洞称为CAS操作的“ABA问题”。

解决方案:JUC包提供了一个带有标记的原子引用类AtomicStampedReference,它可以通过控制变量版本来保证CAS的正确性,但是性能方面还不如互斥同步。

3. 无同步方案

无同步:如果能让一个方法本来就不涉及共享数据,那他自然就不需要任何同步措施去保证其正确性。因此有一些代码天生就是线程安全的。

  • 可重入代码(纯引用):可以在代码执行的任何时刻中断它,转而去执行另一段代码,而在控制权返回后,原来的程序不会出现错误,也不会对结果有所影响。

    判断代码是否具备可重入性:如果一个方法的返回结果是可以预测的,只要输入了相同的数据,就都能返回相同的结果,那它就满足可重入性的要求,当然也就是线程安全的。

  • 线程本地存储:如果一段代码中所需要的数据必须与其他代码共享,那就看看这些共享数据的代码是否能保证在同一个线程中执行。

    常见的:消费队列、服务端请求

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3223627.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

3d模型墙模糊怎么回事?---模大狮模型网

在展览3D模型设计行业中,技术细节常常是设计师们需要面对和解决的关键问题之一。其中,3D模型墙模糊的现象可能会影响整个展览的视觉效果和观众的体验。本文将深入探讨这一问题的起因及解决方法,帮助设计师们更好地处理类似挑战。 一、问题的起…

MySQL架构优化及SQL优化

变更项目的整体架构是性能收益最大的方式。主要涉及两方面,一方面是从整个项目角度,引入一些中间件优化整体性能,另一方面是调整MySQL的部署架构,确保能承载更大的流量访问,提高数据层的整体吞吐。 1. 引入缓存中间件…

不用服务器 | 我搭建了一个属于自己的GPT聊天应用!!!

原文地址:aiutools.fun/archives/5118 平台限制部分内容未显示,详情请访问原文。 展示 不废话,直接上干货! 我这里搭建的Lobe Chat 支持 聊天TTS & STT 语音会话文生图各种优秀的插件 下面搭建好的样子 前期准备 需要…

基于jeecgboot-vue3的Flowable流程-集成仿钉钉流程(四)支持json和xml的显示

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 1、相应的界面前端代码 <template><div class"formDesign"><FlowDesign :process"process" :fields"fields" :readOnly"readOnly&quo…

算法之工程化内容(2)—— Git常用命令

目录 1. git初始化配置 2. 新建仓库 3. 工作区——>暂存区——>本地仓库 4. git reset回退版本 5. 查看差异 git diff 6. 删除文件git rm 7. .gitignore 8. vscode操作git 9. git分支、合并和删除 10. 解决合并冲突 11. 回退和rebase 12. 添加远程仓库 参考链接&#xff…

【少儿编程Python:趣味编程,探索未来】第四章 面向对象编程,开启编程新境界 / 第二节 继承与多态的魔法探险

欢迎进入Python编程的奇幻世界!在这个课程中,我们将一起探索编程的乐趣,通过生动有趣的方式,培养孩子们的逻辑思维和创造力,让他们成为未来的科技小达人。 以下是我们课程的大纲: 【少儿编程Python:趣味编程,探索未来】 目录 1. 命名空间和作用域的探险之旅1.1 命名空间…

【通信协议】八、CDL(Caterpillar Data Link)协议解析

1、协议简介 CDL(Caterpillar Data Link)是caterpillar的通信协议,该品牌发动机ECM与各控制单元进行通信时,采用基于RS-485的物理层规范进行开发的CDL协议进行通信; 2、物理层 信号传输方式:差分信号(通过两条线的电压差识别逻辑0或逻辑1) 通信方式:半双工通信(只允…

Agent如何帮助大模型“增强记忆”?

Agent如何帮助大模型“增强记忆”&#xff1f; 原创 格林 神州问学 2024年07月08日 17:50 日本 记忆反馈 >规划&#xff1f; 来源|神州问学 引言 去年6月份&#xff0c;Lilian发布了关于LLM驱动的Agent的结构和组件&#xff0c;其中包括规划、行动、工具还有记忆&#xff…

电脑清理c盘内存空间怎么清理免费 怎么清理c盘的垃圾文件又不删除有用文件

在计算机使用过程中&#xff0c;随着时间的推移&#xff0c;C盘空间可能会被各种临时文件、缓存和无用的注册表项占用。这不仅会导致C盘空间不足&#xff0c;还可能影响计算机的性能。那么怎么样清理C盘内存空间&#xff0c;怎么样清理C盘的垃圾避开系统文件呢&#xff1f; 一…

用LangGraph、 Ollama,构建个人的 AI Agent

如果你还记得今年的 Google I/O大会&#xff0c;你肯定注意到了他们今年发布的 Astra&#xff0c;一个人工智能体&#xff08;AI Agent&#xff09;。事实上&#xff0c;目前最新的 GPT-4o 也是个 AI Agent。 现在各大科技公司正在投入巨额资金来创建人工智能体&#xff08;AI …

数据结构 实验 3

题目一&#xff1a;最短路径dijkstra算法 一、实验目的 熟练图的邻接矩阵和邻接表表示法掌握图的最短路径Dijkstra算法的基本思想用C语言实现Dijkstra算法 二、实验内容 从键盘输入的数据创建图&#xff08;图的存储结构采用邻接矩阵&#xff09;&#xff0c;设计Dijkstra算…

SCI二区TOP|蜘蛛黄蜂优化算法(SWO)原理及实现【免费获取Matlab代码】

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2023年&#xff0c;M Abdel-Basset受到蜘蛛黄蜂优化社会行为启发&#xff0c;提出了蜘蛛黄蜂优化算法&#xff08;Spider Wasp Optimizer, SWO&#xff09;。 2.算法原理 2.1算法思想 S…

git撤销/返回到某次提交(idea工具 + gitbush)

不多说废话&#xff0c;直接展示使用。 方法一&#xff1a;使用idea工具进行返回 准备某次过度提交 使用idea打开git log 找到要回去的版本 点击右键选到reset 模式选hard&#xff0c;强制回滚 这个时候本地代码已经回归你指定的版本了。 这个时候再进行强制推送&#xff0c…

Flutter Inno Setup 打包 Windows 程序

转载自&#xff1a;flutter桌面应用从开发配置到打包分发 - 掘金 (juejin.cn) 五.打包 1.创建 release 版本的应用 flutter build release 执行完成后&#xff0c; release包位置在项目的build->windows->runer文件夹中 2.应用程序分发 Windows 为 Windows 平台构建…

Linux 利用命名空间创建一个自己的“容器“

Linux 利用命名空间创建一个自己的"容器" 前置条件 创建一个目录存放容器mkdir /myapp准备静态编译busybox&#xff0c;操作系统自带的往往是依赖动态库的(本文使用的debian apt install busybox-static) 开始 使用unshare起一个独立命名空间.# 进入后/myapp目录…

【Linux】System V信号量详解以及semget()、semctl()和semop()函数讲解

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

【电路笔记】-C类放大器

C类放大器 文章目录 C类放大器1、概述2、C类放大介绍3、C类放大器的功能4、C 类放大器的效率5、C类放大器的应用:倍频器6、总结1、概述 尽管存在差异,但我们在之前有关 A 类、B 类和 AB 类放大器的文章中已经看到,这三类放大器是线性或部分线性的,因为它们在放大过程中再现…

证件照片换背景底色 免费 证件照片制作软件免费下载 证件照换衣服软件免费有哪些好用

证件照是我们身份认证的重要凭证&#xff0c;其质量和专业性都很重要。然而&#xff0c;很多时候&#xff0c;由于各种原因&#xff0c;我们可能无法在拍摄证件照时穿上合适的服装&#xff0c;这就给证件照的质量和形象带来了一定的影响。幸运的是&#xff0c;现在市面上出现了…

ER模型理论和三范式

ER模型理论和三范式 各种关系多对一一对一一对多多对多 三范式理论函数依赖完全函数依赖部分函数依赖传递&#xff08;间接&#xff09;函数依赖 第一范式&#xff1a;属性&#xff08;表字段&#xff09;不可切割第二范式&#xff1a;不能存在 部分函数依赖(都存在完全函数依赖…

Git本地仓库的搭建与使用

目录 一、前言 二、Linux下搭建 git 仓库 三、Windows下搭建 git 仓库 一、前言 做项目时&#xff0c;我们常常需要将自己的代码进行托管&#xff0c;但有时候 Github 的速度属实叫人流泪。有的人会选择 Gitee 等进行托管代码&#xff0c;这当然是可以的。那如果没有其他代码…