java多线程(并发)夯实之路-volatile深入浅出

volatile

volatile(易变关键字)可以用来修饰成员变量和静态成员变量,线程只能从主存中获取它的值,线程操作volatile变量都是直接操作主存

与synchronzied区别:synchronzied需要创建Monitor,属于重量级的操作,volatile更轻量(推荐)

可见性

一个线程对主存的数据进行了修改,另一个线程不可见

如下,t线程并不会停下来,因为main线程修改了run值,并同步至主存,但t线程是从自己工作内存中的高速缓存中读取run值,缓存中的run值没变,仍是true(t线程要频繁地访问run的值,JIT编译器会将run值存入高速缓存中,提高效率)

解决方法:给这个变量加volatile修饰,或者用synchronzied         

可见性VS原子性

可见性是修改变量对所有线程可见,线程能得到正确的值,不能保证原子性

原子性是保证一整块操作是不可分割的,否则上下文切换发生线程安全问题 volatile适用一个线程修改变量,多个线程读取变量的情况

synchronzied语句块可以保证代码块的原子性,也可以保证代码块内变量的可见性,缺点是属于重量级操作,性能相对更低

有序性

JVM会在不影响正确性的前提下,调整语句的执行顺序

这一特性被称为指令重排,多线程下指令重排会影响正确性

指令重排原理:每个指令分为五个个阶段,不改变结果的前提下,指令的各个阶段可以通过重排序和组合来实现指令级并行(分阶段,分工是提升效率的关键)

就像

现代CPU支持多级指令流水线,可以同时执行取指令-指令译码-执行指令-内存访问-数据写回的处理器就可以称为五级指令流水线,CPU可以在一个时钟周期内,同时运行五条指令的不同阶段,IPC=1,流水线技术并没有缩短单条指令的执行时间,但变相地提高了指令的吞吐率

指令重排产生的问题:

如以下代码,可能发生指令重排如下右图所示,r值可能为0(很难出现)

解决方案:给ready变量加上volatile

操作volatile变量之前的代码不会重排序

volatile原理

volatile的底层实现是内存屏障,Memory Barrier(Memory Fence)对volatile变量的写指令后会加入写屏障

对volatile变量的读指令前会加入读屏障

保证可见性:

写屏障(sfence)保证该屏障前对共享变量的写入,都同步到主存中

读屏障(lfence)保证该屏障后对共享变量的读取,都从主存中加载

即保证了volatile变量的写操作及之前的写操作,volatile变量读操作及之后的读操作都是在主存中进行的,是准确的。

保证有序性:

写屏障保证指令重排时,写屏障之前的代码不会排在写屏障之后读屏障保证指令重排时,读屏障之后的代码不会排在读屏障之前即指令重排时,写屏障之前和读屏障之后的代码不会跨越屏障

但是并不能解决指令交错(上下文切换),只能保证一个线程中相关变量读写准确,以及一个线程中相关代码不被重排序

double-checked locking问题


以著名的double-checked locking单例模式为例

以上代码的实现特点是:

·懒惰实例化

·首次使用getInstance()才用synchronized加锁,之后不用加锁

·但很关键的一点:第一个if使用INSTANCE变量,在同步块之外

在多线程环境下,代码是有问题的

也许jvm会优化为:INSTANCE = new SIngleton()先赋值再调用SIngleton构造方法。

而在调用SIngleton构造方法前,INSTANCE不为空,可能另一个线程已经去使用INSTANCE对象

synchronzied代码中仍然有指令重排,但如果变量完全被synchronzied保护,就不会有原子性,可见性以及有序性问题

解决方案:给INSTANCE变量加上volatile

happens-before

happens-before规定对共享变量的写操作对其它线程的读操作,它是有序性和可见性的一套规则总结。

抛开以下happens-before规则,JVM并不能保证一个线程对共享变量的写,对于其它线程的读可见:

线程解锁之前对变量的写,对之后其它线程加锁对变量的读是可见的

线程对volatile变量的写,对之后其它线程对该变量的读可见

线程start前对变量的写,对之后线程开始对变量的读可见

线程结束前对变量的写,对其它线程得知它结束后的读可见(如调用t1.join()或 t1.isAlive())

线程被打断前对变量的写,对其它线程得知它被打断后的读可见(通过t1.interrupt()或 t1.isInterruputed())

对变量默认值(0,flase,null)的写,对其它线程对该变量的读可见

具有传递性(如果x hb-> y 并且y hb-> z 那么x hb-> z,配合volatile防止指令重排,有下面的例子)

静态成员变量初始化操作在类加载阶段实现的,类加载阶段由JVM保证代码的线程安全性

可见性问题由JVM缓存优化引起,有序性问题由JVM指令重排优化引起

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

读书笔记——《未来简史》

前言 《未来简史》是以色列历史学家尤瓦尔赫拉利的人类简史三部曲之一。三部分别为《人类简史》《未来简史》《今日简史》。其中最为著名的当然是《人类简史》,非常宏大的一本关于人类文明历史的书籍,绝对可以刷新历史观,《人类简史》这本书…

DAY01_Spring—Spring框架介绍IOCSpring工厂模式

目录 1 什么是框架2 Spring框架2.1 Spring介绍2.2 MVC模型说明2.3 IOC思想2.3.1 问题说明2.3.2 IOC说明 3 Spring IOC具体实现3.1 环境准备3.1.1 关于JDK说明3.1.2 检查JDK环境配置 3.2 创建项目3.3 关于Maven 命令3.3.1 install 命令3.3.2 clean 命令 3.4 添加jar包文件3.4.1 …

云计算平台建设总体技术方案详细参考

第1章. 基本情况 1.1. 项目名称 XX 公司 XX 云计算平台工程。 1.2. 业主公司 XX 公司。 1.3. 项目背景 1.3.1. XX 技术发展方向 XX,即运用计算机、网络和通信等现代信息技术手段,实现政府组织结构和工作流程的优化重组,超越时间、空间…

【AIGC入门一】Transformers 模型结构详解及代码解析

Transformers 开启了NLP一个新时代,注意力模块目前各类大模型的重要结构。作为刚入门LLM的新手,怎么能不感受一下这个“变形金刚的魅力”呢? 目录 Transformers ——Attention is all You Need 背景介绍 模型结构 位置编码 代码实现&…

设计模式之开闭原则:如何优雅地扩展软件系统

在现代软件开发中,设计模式是解决常见问题的最佳实践。其中,开闭原则作为面向对象设计的六大基本原则之一,为软件系统的可维护性和扩展性提供了强大的支持。本文将深入探讨开闭原则的核心理念,以及如何在实际项目中运用这一原则&a…

Rust-借用和生命周期

生命周期 一个变量的生命周期就是它从创建到销毁的整个过程。其实我们在前面已经注意到了这样的现象: 然而,如果一个变量永远只能有唯一一个入口可以访问的话,那就太难使用了。因此,所有权还可以借用。 借用 变量对其管理的内存…

C#编程-自定义属性

命名自定义属性 让我们继续漏洞修复示例,在这个示例中新的自定义属性被命名为BugFixingAttribute。通常的约定是在属性名称后添加单词Attribute。编译器通过允许您调用具有短版名称的属性来支持附加。 因此,可以如以下代码段所示编写该属性: [ BugFixing ( 122,"Sara…

C#用double.TryParse(String, Double)方法将字符串类型数字转换为数值类型

目录 一、定义 二、实例 命名空间: System 程序集: System.Runtime.dll 一、定义 将数字的字符串表示形式转换为它的等效双精度浮点数。 一个指示转换是否成功的返回值。 public static bool TryParse (string? s, out double result…

蓝桥杯备赛 | 洛谷做题打卡day3

蓝桥杯备赛 | 洛谷做题打卡day3 sort函数真的很厉害! 文章目录 蓝桥杯备赛 | 洛谷做题打卡day3sort函数真的很厉害!【深基9.例1】选举学生会题目描述输入格式输出格式样例 #1样例输入 #1 样例输出 #1 我的一些话 【深基9.例1】选举学生会 题目描述 学校…

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 例4-2 常用表单控件

代码 <!doctype html> <html> <head> <meta charset"utf-8"> <title>常用表单控件</title> <style> form {width: 260px;margin: 0 auto;border: 1px solid #ccc;padding: 20px; } .right {float: right; } </style&g…

【学习笔记】2、逻辑代数与硬件描述语言基础

2.1 逻辑代数 &#xff08;1&#xff09;逻辑代数的基本定律和恒等式 基本定律或 “”与 “”非 “—”0-1律A0AA11AAAA A ‾ \overline{A} A1(互补律)A00A1AAAAA A ‾ \overline{A} A0 A ‾ ‾ \overline{\overline{A}} AA结合律(AB)C A(BC)(AB)CA(BC)ABC交换律AB BAABBA分…

广州市生物医药及高端医疗器械产业链大会暨联盟会员大会召开,天空卫士数据安全备受关注

12月20日&#xff0c;广州市生物医药及高端医疗器械产业链大会暨联盟会员大会在广州举办。在本次会议上&#xff0c;作为大会唯一受邀参加主题分享的技术供应商&#xff0c;天空卫士南区技术总监黄军发表《生物制药企业如何保护数据安全》的主题演讲。 做好承上启下“连心桥”…

【Spring实战】29 @Value 注解

文章目录 1. 定义2. 好处3. 示例1&#xff09;注入基本类型2&#xff09;注入集合类型3&#xff09;使用默认值4&#xff09;注入整数和其他类型 总结 在实际的应用中&#xff0c;我们经常需要从外部配置文件或其他配置源中获取参数值。Spring 框架提供了 Value 注解&#xff0…

感染了后缀为.mallox勒索病毒如何应对?数据能够恢复吗?

尊敬的读者&#xff1a; 在数字时代&#xff0c;勒索病毒如.mallox已经成为网络威胁中的重要一环。这篇文章将深入介绍.mallox勒索病毒的特征、应对策略以及如何预防这一威胁。面对复杂的勒索病毒&#xff0c;您需要数据恢复专家作为坚强后盾。我们的专业团队&#xff08;技术…

adb wifi 远程调试 安卓手机 命令

使用adb wifi 模式调试需要满足以下前提条件&#xff1a; 手机 和 PC 需要在同一局域网下。手机需要开启开发者模式&#xff0c;然后打开 USB 调试模式。 具体操作步骤如下&#xff1a; 将安卓手机通过 USB 线连接到 PC。&#xff08;连接的时候&#xff0c;会弹出请求&#x…

收银系统源码-智慧新零售系统框架

智慧新零售系统是一套线下线上打通的收银系统&#xff0c;主要给门店提供含线下收银、线上小程序商城、ERP进销存、精细化会员管理、丰富营销插件等为一体的智慧行业解决方案。智慧新零售系统有合伙人、代理商、商户、门店、收银员/导购员等角色&#xff0c;每个角色有相应的权…

Fine-tuning:个性化AI的妙术

在本篇文章中&#xff0c;我们将深入探讨Fine-tuning的概念、原理以及如何在实际项目中运用它&#xff0c;以此为初学者提供一份入门级的指南。 一、什么是大模型 ChatGPT大模型今年可谓是大火&#xff0c;在正式介绍大模型微调技术之前&#xff0c;为了方便大家理解&#xf…

C++系统笔记教程----vscode远程连接ssh

C系统笔记教程 文章目录 C系统笔记教程前言开发环境配置总结 前言 开发环境配置 Ubuntu20.24VScode 如果没有linux系统&#xff0c;但是想用其编译&#xff0c;可以使用ssh远程连接。 首先进入vscode,打开远程连接窗口&#xff08;蓝色的小箭头这&#xff09; 选择连接到主机…

Redis主从架构、哨兵集群原理实战

1.主从架构简介 背景 单机部署简单&#xff0c;但是可靠性低&#xff0c;且不能很好利用CPU多核处理能力生产环境必须要保证高可用&#xff0c;一般不可能单机部署读写分离是可用性要求不高、性能要求较高、数据规模小的情况 目标 读写分离&#xff0c;扩展主节点的读能力&…

案例:应用内字体大小调节

文章目录 介绍相关概念完整实例 代码结构解读保存默认大小获取字体大小修改字体大小 介绍 本篇Codelab将介绍如何使用基础组件Slider&#xff0c;通过拖动滑块调节应用内字体大小。要求完成以下功能&#xff1a; 实现两个页面的UX&#xff1a;主页面和字体大小调节页面。拖动…