Volatile并发理解

一步到位解决Docker拉取镜像失败的问题!超详细的Docker代理设置教程!(使用代理解决群晖Docker获取注册表失败的问题) 阅读详情

Volatile作用

在java中主要用来修饰成员变量和类变量。其中,使用volatile修饰的变量在多线程环境中对所有多线程都是可见的。即,其中一个线程修改了volatile修饰的变量值,则其他线程能够立即得到最新修改的值。对于这个方面的理解,可以从并发编程模型(CPU,缓存,内存)和JAVA内存模型两个方面分析。

并发编程模型

现在的服务器都是多核的,而应用的都是发生在多线程环境中,那么在多核服务器中,多个处理器之间是如何与同一块内存中的数据进行交互呢?这就要先了解一下硬件层面的结构模型:
这里写图片描述
通过上述图中,可以发现在一个多核的服务器中,每一个处理器都有一块单独属于自己的缓存空间。每个线程将内存中的数据读取到高速缓存中进行运算操作,等待运算完再降变量值重写入内存中。
当多个cpu并发处理同一个变量时,是如何做到缓存之间变量值的同步呢?这就要求多个处理器之间遵守缓存协议(引用他人文章解释):
最出名的就是Intel 的MESI协议,MESI协议保证了每个缓存中使用的共享变量的副本是一致的。它核心的思想是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。
这里写图片描述

java内存模型

java内存模型跟上面OS并发编程模型相似,也是分为主内存,工作内存,线程。其中,每个线程都有自己的工作内存。对于共享变量i,每个线程操作时都会将其拷贝一份到工作内存,每个线程操作的都是工作内存中的变量,禁止直接操作主内存中的数据。内存模型如下:
这里写图片描述
根据内存模型,可以看出对于主内存中的共享变量,每个线程都会有一个关于该共享变量的副本拷贝在其工作内存区。线程修改共享变量的值只能发生在工作内存区,等修改完毕后,会将最新值rewrite到主内存中。
对于单线程操作肯定是没有问题的,但是对多线程的操作,程序的执行结果就很容易发生错误。当然,对于多线程,在java中可以有很多种方式避免,比如同步(synchronized,lock,volatile)都可以做到同步。关于java内存模型可以看看我另外一篇分享的文章

volatile深探

看完上诉并发编程模型和java内存模型简单分析之后,应该大致对并发编程处理机制有个初步的了解。volatile在修饰变量(成员变量,类变量)到底起到什么作用,可以通过三个方面进行分析:

原子性

原子操作对于并发编程来说无疑是最重要的操作。原子操作指示要么全部成功要么全部失败。volatile修饰的变量对于其他线程是可见的,但是变量的操作不是原子操作。只有基本类型操作(赋值,读取)才是原子性操作。其他类型变量或基本类型的运算操作都是非原子操作。通过代码演示volatile修饰变量的非原子性操作:
public class SingletonInstance {

    private volatile static SingletonInstance instance = null;

    private SingletonInstance(){}

    public static SingletonInstance getInstance (){
        if(null == instance){    
            instance = new  SingletonInstance();
        }
        return instance;
    }
}

上述代码是想实现一个单例模式,即多线程环境下生成的SingletonInstance实例是唯一的。看看调用代码:

public class SingletonInstanceTest {

    public static void main(String[] args) {
        for(int i=0;i<30;i++){
             new Thread(new ThreadDemo()).start();
        }
    }
}

class ThreadDemo implements Runnable{
    public void run() {
        System.out.println(SingletonInstance.getInstance());
    }

}

上述多线程环境下运行程序结果如下:
这里写图片描述
可以看到在上述环境下使用volatile修饰的变量并不能做到线程安全。就是因为里面涉及了非原子的操作。下面通过一张图来理解volatile的执行原理:
这里写图片描述
1. 根据图中流程,线程A将主内存变量拷贝到工作内存经过运算之后再同步到主内存主要经过了8个步骤。
2. read:线程从主内存将共享变量var值(初始化一定在主内存完成)读取到工作内存,即结束。
3. load:线程执行完read操作之后就跟主内存变量没有关系。load是将主内存变量值赋给工作内存中的变量副本
4. use:使用load操作完工作内存中的变量副本,进行一定的运算。
5. assign:将use动作运算的结果赋值给变量副本var_v。
6. store:将新的运算结果的变量值存储到主内存。
7. write:作用于主内存变量,把store存储的值重新赋给主内存变量。
通过上述分析,可以发现volatile修饰的变量只是解决了变量在读取时对于所有 线程都是可见的。但是后续对于变量的操作不是原子性的。多线程对于volatile修饰 变量操作问题,还是需要通过加锁进行同步。这也就解释了上述程序中,为什么多线程环境中获得SingletonInstance的实例不是唯一的。
工作线程每次操作volatile修饰的变量,都需要先从主内存刷新最新的变量值,用于保证其他线程对该变量修改的可见性

可见性

  1. volatile修饰变量对于多线程读取时是可见的。也就是说如果线程A修改了共享变量var的值,线程B,C,D再次读取时,一定能够读取到最新的var值。因为使用volatile修饰的变量值,如果发生了改变,就会立即同步到内存。同理,其他线程每次读取该变量时都要重新从主内存读取。
    这里写图片描述

有序性

JVM中对于某一些规定有着天然有序性.这种有序性实在某些条件下才会成立的。在使用volatile修饰后,JVM遵从如下有序性:
1. 程序代码中volatile修饰变量V前的代码一定优先发生在V之前执行,不会在V之后执行。
2. 程序代码中V之后定义的代码一定在V之后执行,绝对不会在V之前执行。

总结

  1. volatile是JAVA中最轻量级的同步机制,只能是修饰变量,不能修饰方法和代码块
  2. volatile修饰的变量对于所有线程读取时是可见的,即一个线程对共享变量值的修改对于其他线程再次读取时是可见的。
  3. volatile修饰的变量在多线程环境中的操作是非原子性的,需要使用加锁进行同步。

参考资料

JAVA多线程编程核心艺术
深入理解JVM虚拟机
http://www.cnblogs.com/dolphin0520/p/3920373.html

javascript 酷炫时钟 javascript 酷炫时钟 阅读详情

相关推荐

用Python和sklearn预测NBA比赛胜负:从数据清洗到模型优化的完整流程

本文详细介绍了如何使用Python和sklearn构建NBA比赛胜负预测模型,涵盖从数据清洗、特征工程到模型优化与部署的完整流程。通过对比随机森林、XGBoost等主流算法,提供实战技巧和解决方案,帮助数据爱好者掌握体育数据分析的核心技术。

weixin_30823001的博客 132

并发编程--volatile详解

一、volatile的定义 Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。Java语言 提供了volatile,在某些情况下比锁要更加方便。如果一个字段被声明成volatile,Java线程内存模型确保所有线程看到这个变量的值是一致的。 二、Java内存模型(JMM) 现代计算机的内存模型 其实早期计算机中cpu和内存的速度是差不多的,但在现代计算机中,cpu的指令速度远超内存的存取速度,由于计算机的存储设备与处理器的运算.

zhang09090606的博客 361

stm32f103c8t6的中文字库

stm32的成熟中文字库,上手即用,操作简单

nbbskk的博客 3653

【JUC】volatile关键字相关整理

聊volatile关键字之前得先补充一些基本概念–JMM(java内存模型) JMM,一种抽象的概念,Java并发采用它作为共享内存模型:定义了Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式。JVM是整个计算机虚拟模型,所以JMM是隶属于JVM。 由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方成为栈空间),工作内存是每个线程的私有数据区域,而...

aaa_bbb_ccc_123_456的博客 2596

pytorchDataLoader中调整数据长度不一致问题(lstm等)

数据长度不一致 用pytorch做rnn的时候,如果输入数据不一样长,可以用两种方式解决。 一种是自定义collate方法, #自定义collate_fn dataloader.DataLoader(dataset,4,True,collate_fn=my_collate) 然后里面写数据和标签载入方式即可 def my_collate(batch): data = [item[0] for item in batch] target = [item[1] for item in batc

weixin_48174100的博客 7770

DSP配置I2C通讯(非IO口软件模拟时序)

dsp即数字信号处理器,是一种广泛应用的嵌入式处理器,主要应用是实时快速地实现各种数字信号处理算法,目前,国际主要的dsp供应商是ti公司,其tms32系列产品占据了dsp市场近一半的份额,本文以TMS320F28377D为例,使用ti公司dsp开发工具ccs10.1配置i2c模块。 写这篇文章的缘由,因为市面上很多DSP其实内部是具有硬件I2C接口的,但由于网络上大部分资料和例程都是利用IO口模拟I2C时序进而实现I2C通讯的。给很多想学习硬件I2C通讯的小伙伴带来了困难。 下面先介绍一下配置步骤 1.E

weixin_44387442的博客 5545

并发系列之volatile解析

并发系列之volatile解析1、volatile简介2、可见性3、有序性4、往期佳文4.1、面试系列4.2、技术系列4.3、源码系列4.4、数据结构和算法系列4.5、多线程系列 1、volatile简介        volatile 具有可见性和有序性的特性,同时,对 volatile 修饰的变量进行单个读写操作是具有原子性。 2、可见性        简单的说,就

Java学习之乐的博客 415

mmpretrain学习笔记

(4)数据集路径 data_root=‘data/imagenet’–》data_root=‘data/Fruits Dataset/images’(7)适当的修改num_workers、epochs、batch_size、lr等。3、训练优化 :梯度下降算法、学习率参数、训练总轮次、学习率变化策略等。my_resnet18_8xb32_in1k.py 完整的配置文件。(6)split=‘train’、split='val’注释掉。2、数据:数据集划分、数据文件路径、批大小、数据增强策略等。

吃葡萄不吐葡萄皮 937

Java并发编程:volatile关键字解析

volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在Java 5之后,volatile关键字才得以重获生机。 volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情...

chizhi3010的博客 172

别再乱删文件了!修复Print Spooler服务自动停止的3个关键检查点(附Win10/Win11实测)

本文深入解析Windows系统中Print Spooler服务自动停止的常见原因及修复方法。从第三方驱动冲突、权限与服务依赖关系到打印队列积压,提供3个关键检查点的详细排查步骤,帮助用户彻底解决打印服务异常问题,适用于Win10/Win11系统。

weixin_31569671的博客 674

ROS机器人未知环境自主探索功能包explore_lite最全源码详细解析(二)

本系列文章主要针对ROS机器人常使用的未知环境自主探索功能包explore_lite展开全源码的详细解析,并进行概括总结。 本系列文章共包含六篇文章,前五篇文章主要介绍explore_lite功能包中 explore.cpp、costmap_tools.h、frontier_search.cpp、costmap_client.cpp等源码实现文件中全部函数的详细介绍,第六篇文章进行概括总结,包含自主探索功能包explore_lite的简介,实现未知环境自主探索功能的原理及流程总结,效果演示,使用功能包exp

慕羽★的博客 1648

面试官:请说下volatile的实现原理

volatile是面试中的高频问题,这篇文章能带你详细了解volatile的面试相关问题 微信搜索公众号路人zhang,回复面试手册,领取更多高频面试题PDF版及更多面试资料。 推荐阅读: MySQL数据库高频面试题 计算机网络高频面试题最新版 Java集合高频面试题最新版 并发编程高频面试题 面试官:请用五种方法实现多线程交替打印问题 面试官:请详细说下synchronized的实现原理 文章目录volatile的作用是什么?volatile的特性有哪些?Java内存的可见性问题为什么代码会重排序.

zydybaby的博客 819

7、布尔网络的基础定义

本文介绍了布尔网络的基础定义及其在系统生物学中的应用。布尔网络是一种描述复杂系统动态行为的数学模型,由布尔变量和布尔函数组成,能够模拟生物系统中基因调控、信号传导和细胞代谢等过程。文章详细阐述了布尔网络的基本结构、动力学特征(如状态转移图和吸引子),以及其在生物建模中的重要价值,并探讨了优化和简化技术(如Backward Boolean Equivalence)如何提升其计算效率。

yhn45678901的博客 262

9、你应该理解的java并发关键字volatile

提高java的并发编程,就不得不提volatile关键字,不管是在面试还是实际开发中 volatile都是一个应该掌握的技能。他的重要性不言而喻。因此也有必要学好。 一、为什么要用到volatile关键字? 使用一个新技术的原因肯定是当前存在了很多问题,在Java多线程的开发中有三种特性:原子性、可见性和有序性。我们可以在这里简单的说一下: 1、原子性(Atomicity) 原子性是指在一个操作中...

冯冬冬的博客 446

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

彻底理解Java并发:volatile关键字

本篇内容包括:volatile 关键字简介、volatile 保证可见性(包括:关乎不可见性问题描述、JMM内存模型和不可见性的解决方案)以及 volatile 其他特性(包括:volatile 不保证原子性、volatile 原子性的保证操作、volatile 禁止指令重排、内存屏障和 happens-before 规则)

栗筝i的博客 6257

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

你应该要理解的java并发关键字volatile

提高java的并发编程,就不得不提volatile关键字,不管是在面试还是实际开发中 volatile都是一个应该掌握的技能。他的重要性不言而喻。因此也有必要学好。 一、为什么要用到volatile关键字? 使用一个新技术的原因肯定是当前存在了很多问题,在Java多线程的开发中有三种特性:原子性、可见性和有序性。我们可以在这里简单的说一下: 1、原子性(Atomicity) 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行,就好比你做一件事,要么

徐泗空的博客 254

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

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

并发(二)——volatile理解

首先,确定一点就是volatile不具备原子性,但是拥有可见性,并且在一定程度上拥有有序性。 不具备原子性的原因: 因为可以认为是三个步骤 根据jmm理解,从主内存获取变量的值,并将其放入线程工作内存 工作区中的变量副本执行加一操作 再将工作内存写入主内存 其中线程一和线程二有可能同时执行1,然后再执行2,3步骤的时候,就会重复赋同样的值。 可见性和有序性原因 volati...

sgnever的专栏 309

[并发]如何彻底理解volatile关键字

初识volatile 下面就让我们循序渐进地逐步了解volatile关键字吧!先了解下volatile的关键字都用在代码的什么地方:"volatile关键字只能修饰类变量和实例变量。方法参数、局部变量、实例常量以及类常量都是不能用volatile关键字进行修饰的"。 问题(1):“为什么volatile关键字只能修饰类变量和实例变量呢?”关于问题,我们可以先进行思考,然后在文章的结尾集中...

疯一样的女子 213

Java并发编程之volatile的理解

Java并发编程之volatile关键字的理解 Java中每个线程都有自己的工作内存,类比于处理器的缓存,线程的工作内存中保存了被该线程使用到的变量的主内存的拷贝。线程读写变量都是直接在自己的工作内存中进行的,而何时刷新数据(指将修改的结果更新到主存或者把主存的变量读取...

chuanjinju8954的博客 67

Java并发编程之深入理解volatile

个人博客请访问http://www.x0100.top 1. 保证可见性 volatile保证了不同线程对volatile修饰变量进行操作时的可见性。 对一个volatile变量的读,(任意线程)总是能看到对这个volatile变量最后的写入。 一个线程修改volatile变量的值时,该变量的新值会立即刷新到主内存中,这个新值对其他线程来说是立即可见的。 一个线程读取volatile变量的值时,该变量在本地内存中缓存无效,需要到主内存中读取。 举例: 中断线程时常...

HelloWorld搬运工 349

理解volatile:并发编程的核心机制

摘要:volatile是Java并发编程中的轻量级同步机制,主要解决多线程环境下的可见性和有序性问题。它通过内存屏障禁止指令重排序,保证变量修改对其他线程立即可见。典型应用场景包括状态标志、双重检查锁定和一次性发布等模式。但需注意volatile只能保证单次读写的原子性,无法确保复合操作(如i++)的线程安全。在32位系统中,volatile还能保证long/double变量的原子性访问。正确使用volatile可以编写更高效安全的并发代码,复杂场景仍需结合synchronized或原子类。

weixin_50701238的博客 977

JAVA并发理解之volatile、synchronized和lock解析

       谈到并发时候,离不开JAVA的几个关键字volatile、synchronized和lock类。下面就分别介绍一下它们的实现原理、用法以及使用场景。      首先先了解一下Java内存模型的抽象示意如图所示      *每个线程都有自己的本地内存空间(java栈中的帧)。线程执行时,先把变量从内存读到线程自己的本地内存空间,然后对变量进行操作。       * 对该变量操作完成后,...

不行就改名 928

JAVA并发六:彻底理解volatile

原博地址:https://www.javazhiyin.com/887.html 1. volatile简介 在上一篇文章中我们深入理解了java关键字,我们知道在java中还有一大神器就是关键volatile,可以说是和synchronized各领风骚,其中奥妙,我们来共同探讨下。 通过上一篇的文章我们了解到synchronized是阻塞式同步,在线程竞争激烈的情况下会升级为重量级锁。而volatile就可以说是java虚拟机提供的最轻量级的同步机制。但它同时不容易被正确理解,也至于在并发编程中很多程序员

今天的BUG保熟。 199

Java并发编程volatile关键字理解

Java并发编程volatile关键字理解 一、volatile是什么? volatile是jvm提供的轻量级的同步机制,它具有三大特性分别是:保证可见性、禁止指令重排序、不保证原子性。说到这三大特性还得提到JMM(java内存模型)。 1、JMM 每个线程创建时,jvm都会为其分配一个工作内存,这个工作内存是每个线程私有空间,然而我们定义的所有变量都是存在主内存中,主内存是共享的内存区域,创建的线程都可以访问,但是线程对于变量的操作,必须先将变量从主内存拷贝一份到自己的工作内存,然后才能对其进行操作,操作

weixin_43901749的博客 362

多线程与并发:从JMM设计中理解volatile

JMM :Java Memory Model 要理解JMM,要先从计算机底层开始 如果我们计算一次a+b所需要的的时间: CPU读取内存获得a,100纳秒 CPU读取内存获得b,100纳秒 CPU执行一条指令 a+b ,0.6纳秒 也就是说主要的时间花费在CPU读取内存上了,所以在当代CPU里面引入了高速缓存 ...

临木的博客 255

并发编程之___请谈谈你对volatile的理解?

三个特性:volatile是JVM提供的轻量级线程同步机制。 可见性 根据JMM模型,两个线程同时操作同一个变量时,当一个线程对其进行修改后,那么可以保证另一个线程可见。 JMM概念: JMM本身是一种抽象的概念,并不真实存在的,它描述的是一组规则或规范,通过这组规范定义程序中各个变量(包括实例字段,静态字段,和构成数组对象的元素...

Coinker的博客 249
上一篇: Redis持久化学习
下一篇: 生产者消费者(singlAll和await误用)
鸡蛋达芬奇
博客等级 码龄19年 24粉丝 34原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值