详解 Java 中的 volatile 关键字

引言:

        在 Java 编程中,volatile 是一个非常重要的关键字,用于修饰变量。它主要用于确保多个线程之间对共享变量的修改能够被及时地更新到主内存,并且能够保证可见性。然而,需要注意的是,volatile 关键字并不具备原子性,这就意味着在某些情况下,仅仅使用 volatile 是不足够的。本文将深入探讨 volatile 关键字的使用及其特性。

一、volatile 能保证内存可见性  

代码在写⼊ volatile 修饰的变量的时候,
  • 改变线程⼯作内存中volatile变量副本的值
  • 将改变后的副本的值从⼯作内存刷新到主内存
代码在读取 volatile 修饰的变量的时候,
  • 从主内存中读取volatile变量的最新值到线程的⼯作内存中
  • 从⼯作内存中读取volatile变量的副本
前⾯我们讨论内存可⻅性时说了, 直接访问⼯作内存(实际是 CPU 的寄存器或者 CPU 的缓存), 速度⾮常快, 但是可能出现数据不⼀致的情况.
加上 volatile , 强制读写内存. 速度是慢了, 但是数据变的更准确了.

 代码示例:

  • 创建两个线程 t1 和 t2
  • t1 中包含⼀个循环, 这个循环以 flag == 0 为循环条件.
  • t2 中从键盘读⼊⼀个整数, 并把这个整数赋值给 flag
  • 预期当⽤⼾输⼊⾮ 0 的值的时候, t1 线程结束
        static class Counter {public int flag = 0;}public static void main(String[] args) {Counter counter = new Counter();Thread t1 = new Thread(() -> {while (counter.flag == 0) {// do nothing}System.out.println("循环结束!");});Thread t2 = new Thread(() -> {Scanner scanner = new Scanner(System.in);System.out.println("输⼊⼀个整数:");counter.flag = scanner.nextInt();});t1.start();t2.start();}
    // 执⾏效果
    // 当⽤⼾输⼊⾮0值时, t1 线程循环不会结束. (这显然是⼀个 bug)
    t1 读的是⾃⼰⼯作内存中的内容.
    当 t2 对 flag 变量进⾏修改, 此时 t1 感知不到 flag 的变化.

如果给 flag 加上 volatile 

static class Counter {public volatile int flag = 0;
}
// 执⾏效果
// 当⽤⼾输⼊⾮0值时, t1 线程循环能够⽴即结束.

二、volatile 不保证原子性  

        虽然 volatile 能够保证内存可见性,但它并不具备原子性。这意味着,当多个线程同时修改一个 volatile 变量时,可能会出现竞态条件,导致最终结果不符合预期。因此,在需要进行原子性操作时,还需要额外的同步机制,比如 synchronized 关键字或者 java.util.concurrent.atomic 包中提供的原子类。 

代码示例:

  • 给 increase ⽅法去掉 synchronized
  • 给 count 加上 volatile 关键字.
    static class Counter {volatile public int count = 0;void increase() {count++;}}public static void main(String[] args) throws InterruptedException {final Counter counter = new Counter();Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {counter.increase();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {counter.increase();}});t1.start();t2.start();t1.join();t2.join();System.out.println(counter.count);}
    此时可以看到, 最终 count 的值仍然⽆法保证是 100000.

 总结:

   volatile 关键字在多线程编程中扮演着重要的角色,它能够确保共享变量的可见性,但并不保证原子性。因此,在编写多线程程序时,需要根据具体情况综合考虑是否需要额外的同步措施,以确保程序的正确性和稳定性。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PS之更换背景色

1.更换背景色 导入图片后, 选中快速选择工具, 依次点击 选择主体 -> 选择并遮住 其后右边会出现一栏 “属性”, 拉到最下面的 “输出设置”, 选择净化颜色, 然后确认 此时应该得到抠出来的物体. 右下角点击新建图层 此时对图层2打开拾色器, 将图层2 设为白色 然后CTRL…

二维码门楼牌管理应用平台:创新管理与服务的全新方式

文章目录 前言一、二维码门楼牌管理应用平台的建设背景二、二维码门楼牌管理应用平台的功能特点三、切换功能在城市管理中的应用四、二维码门楼牌管理应用平台的未来展望 前言 在数字化时代的浪潮中&#xff0c;二维码技术以其便捷、高效的特点&#xff0c;正逐渐渗透到我们生…

ArrayList和LinkedList的区别【大白话Java面试题】

ArrayList和LinkedList的区别【大白话Java面试题】 大白话回答 arraylist和linkedlist的区别是&#xff1a;数据结构不同&#xff0c;效率不同&#xff0c;自由性不同&#xff0c;主要控件开销不同 数据结构不同 ArrayList是Array(动态数组)的数据结构&#xff0c;LinkedList…

leetcode 周赛 391场

2. 换水问题 给你两个整数 numBottles 和 numExchange 。 numBottles 代表你最初拥有的满水瓶数量。在一次操作中&#xff0c;你可以执行以下操作之一&#xff1a; 喝掉任意数量的满水瓶&#xff0c;使它们变成空水瓶。用 numExchange 个空水瓶交换一个满水瓶。然后&#xf…

JAM计数法C++

题目&#xff1a; 代码&#xff1a; #include <iostream> using namespace std; int main() {int s,t,w;cin>>s>>t>>w;char a[26];cin>>a; //输入给出的jam数字for(int i1;i<5;i) //循环找哪个字母递增{for(int jw-1;j>0;j--){if(a[j]1&…

【41-60】计算机网络基础知识(非常详细)从零基础入门到精通,看完这一篇就够了

【41-60】计算机网络基础知识&#xff08;非常详细&#xff09;从零基础入门到精通&#xff0c;看完这一篇就够了 以下是本文参考的资料 欢迎大家查收原版 本版本仅作个人笔记使用41、使用 Session 的过程是怎样的&#xff1f;42、Session和cookie应该如何去选择&#xff08;适…

知识蒸馏详解及pytorch官网demo案例

知识蒸馏Knowledge Distillation(KD) 1、简介 一种模型压缩方法 知识蒸馏的一般框架&#xff08;如下图&#xff09; 三部分&#xff1a;知识、蒸馏算法、师生架构。 知识 将知识分为三种形式&#xff1a;基于响应的&#xff08;response-based&#xff09;、基于特征的&…

数字乡村发展蓝图:科技赋能农村实现全面振兴

目录 一、数字乡村发展蓝图的内涵与目标 二、科技赋能农村&#xff1a;数字乡村发展的动力与路径 &#xff08;一&#xff09;加强农业科技创新&#xff0c;提升农业生产效率 &#xff08;二&#xff09;推进农村电商发展&#xff0c;拓宽农民增收渠道 &#xff08;三&…

MHA高可用配置与故障切换

前言&#xff1a; MHA高可用故障就是单点故障&#xff0c;那么我们如何解决单点故障MHA中Master如何将故障的机器停止&#xff0c;使用备用的Slave服务器 一 MHA定义 MHA&#xff08;MasterHigh Availablity&#xff09;是一套优秀的Mysql高可用环境下故障切换和主从复制的…

【Linux】进程程序替换 做一个简易的shell

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 文章目录 前言 进程程序替换 替换原理 先看代码和现象 替换函数 第一个execl()&#xff1a; 第二个execv()&#xff1a; 第三个execvp()&#xff1a; 第四个execvpe()&a…

编程语言|C语言——C语言操作符的详细解释

这篇文章主要详细介绍了C语言的操作符&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值&#xff0c;需要的朋友们下面随着小编来一起学习学习吧 一、基础 1.1 算数操作符 - * / % - * / 这些操作符是我们…

QT初识(1)

QT初识 桌面开发什么是QT下载QT安装好之后的工具AssisantDesignerQT Creator 创建一个简单的项目 我们今天来认识一下QT。 桌面开发 在了解QT&#xff0c;我们得了解一下桌面开发&#xff1a; 桌面开发指的是编写和构建在个人计算机或其他桌面操作系统&#xff08;如Windows、…

关系网络c++

题目&#xff1a; 代码&#xff1a; #include<bits/stdc.h>using namespace std;int n,x,y;struct node{int num;//编号 int t;//步数 node(){}node(int sum,int tt){numsum;ttt;} }; int mp[101][101];//图 bool flag[101];//标记 queue<node> q; void bfs() {q…

【Docker】Windows中打包dockerfile镜像导入到Linux

【Docker】Windows中打包dockerfile镜像导入到Linux 大家好 我是寸铁&#x1f44a; 总结了一篇【Docker】Windows中打包dockerfile镜像导入到Linux✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 今天遇到一个新需求&#xff0c;如何将Windows中打包好的dockerfile镜像给迁移…

Autodesk Maya 2025---智能建模与动画创新,重塑创意工作流程

Autodesk Maya 2025是一款顶尖的三维动画软件&#xff0c;广泛应用于影视广告、角色动画、电影特技等领域。新版本在功能上进行了全面升级&#xff0c;新增了对Apple芯片的支持&#xff0c;建模、绑定和角色动画等方面的功能也更加出色。 在功能特色方面&#xff0c;Maya 2025…

equals()和hashcode()的区别【大白话Java面试题】

equals()和hashcode()的区别 大白话 1.equals()&#xff1a;反应的是对象或变量具体的值&#xff0c;及两个对象包含的具体的值&#xff08;可能是对象的引用&#xff0c;也可能是值类型的值&#xff09; 2.hashcode():计算两个对象的哈希值&#xff0c;并返回哈希码&#xff…

逆向分析之antibot

现在太卷了&#xff0c;没资源&#xff0c;很难接到好活&#xff0c;今天群里看到个单子&#xff0c;分析了下能做&#xff0c;结果忙活了一小会&#xff0c;幸好问了下&#xff0c;人家同时有多个人再做&#xff0c;直接就拒绝再继续了。就这次忘了收定金了&#xff0c;所以原…

使用python实现i茅台自动预约

使用python实现i茅台自动预约[仅限于学习,不可商用] 运行: 直接运行 imtApi.py 打包:切换到imt脚本目录,执行打包命令: pyinstaller --onefile imtApi.py这个应用程序可以帮助你进行茅台自动化配置。以下是一些使用说明: 平台注册账号(可用i茅台)不用登录,你可以进行…

Linux的VirtualBox中USB设备无法选择USB3.0怎么办?

在VirtualBox中&#xff0c;如果遇到USB设备无法选择 USB 3.0 的问题&#xff0c;可以尝试按照以下步骤来解决&#xff1a; 确保VirtualBox版本支持USB 3.0&#xff1a;首先&#xff0c;你需要确认你的VirtualBox版本是否支持USB 3.0。一些较旧的版本可能不支持&#xff0c;因此…

一篇搞定AVL树+旋转【附图详解旋转思想】

&#x1f389;个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名乐于分享在学习道路上收获的大二在校生 &#x1f648;个人主页&#x1f389;&#xff1a;GOTXX &#x1f43c;个人WeChat&#xff1a;ILXOXVJE &#x1f43c;本文由GOTXX原创&#xff0c;首发CSDN&…