当前位置: 首页 > news >正文

Java中volatile关键字

        保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的,volatile关键字会强制将修改的值立即写入主存。

1.volatile的可见性

一个典型的例子:永不停止的循环。

    public class ForeverLoop {static boolean stop = false;public static void main(String[] args) {new Thread(() -> {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}stop = true;System.out.println("modify stop to true...");}).start();foo();}static void foo() {int i = 0;while (!stop) {i++;}System.out.println("stopped... c:" + i);}}

当执行上述代码的时候,发现foo()方法中的循环是结束不了的,也就说读取不到共享变量的值结束循环。

主要是因为在JVM虚拟机中有一个JIT(即时编辑器)给代码做了优化。

上述代码:

while (!stop) {
i++;
}

在很短的时间内,这个代码执行的次数太多了,当达到了一个阈值,JIT就会 优化此代码,如下:

while (true) {
i++;
}

当把代码优化成这样子以后,及时 stop 变量改变为了 false 也依然停止不了循环。

解决方案

在修饰 stop 变量的时候加上 volatile ,表示当前代码禁用了即时编辑器,问题就可以解决,代码如下:

static volatile boolean stop = false;

2.指令重排序问题

出现该问题的原因

简单说就是JVM为了对代码进行优化提高性能会在不影响结果的情况下把代码执行顺序改变,但多线程就可能会出现结果不对的问题。

解决方案:添加volatile关键字

volatile原理就是加了一些屏障,使屏障后的代码一定不会比屏障前的代码先执行,从而实现有序性。

给变量y添加关键字的屏障添加的示意图:

写操作加的屏障是阻止上方其它写操作越过屏障排到volatile变量写之下(阻止了 x = 1 走到 y = 1 之后)

读操作加的屏障是阻止下方其它读操作越过屏障排到volatile变量读之上(同上,x 的读,走到 y 的读之前)

补充:为什么不能给x变量添加关键字?

给变量x添加关键字的屏障添加的示意图

这样显然是不行的,主要是因为下面两个原则:

        1.写操作加的屏障是阻止上方其它写操作越过屏障排到volatile变量写之下(这个屏障只能阻止 x = 1;y = 1;这两行代码上方的指令越过该屏障,它不能阻止 y = 1;往上走到 x = 1;之前!)

        2.读操作加的屏障是阻止下方其它读操作越过屏障排到volatile变量读之上

所以,现在我们就可以总结一个volatile使用的小妙招:

        写变量让volatile修饰的变量的在代码最后位置

        读变量让volatile修饰的变量的在代码最开始位置

相关文章:

  • 英语学习笔记22——Give me/him/her/us/them a .... Which one?
  • js处理服务器响应Blob对象格式文件处理
  • 【Unity】免费的高亮插件——QuickOutline
  • 【全开源】JAVA同城搬家系统源码小程序APP源码
  • Scrapy框架简单介绍及Scrapy项目编写详细步骤(Scrapy框架爬取豆瓣网站示例)
  • 在Ubuntu系统中使用Systemctl添加启动项的详细指南
  • Mybatis入门——其他查询操作和数据库连接池(4)
  • 【oracle】Oracle RAC中的GNS到底是什么?
  • ctfshow web入门 黑盒测试
  • linux input 驱动
  • 持续总结中!2024年面试必问 20 道 Rocket MQ面试题(二)
  • 语言模型的发展
  • 磁盘管理以及文件系统08
  • Python二叉树遍历算法
  • 防御恶意爬虫攻击
  • 时间复杂度分析经典问题——最大子序列和
  • 【翻译】babel对TC39装饰器草案的实现
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • Java,console输出实时的转向GUI textbox
  • JavaWeb(学习笔记二)
  • mysql_config not found
  • Spark RDD学习: aggregate函数
  • Vue2.0 实现互斥
  • 湖南卫视:中国白领因网络偷菜成当代最寂寞的人?
  • 面试总结JavaScript篇
  • scrapy中间件源码分析及常用中间件大全
  • 策略 : 一文教你成为人工智能(AI)领域专家
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • $forceUpdate()函数
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (2024)docker-compose实战 (9)部署多项目环境(LAMP+react+vue+redis+mysql+nginx)
  • (3)医疗图像处理:MRI磁共振成像-快速采集--(杨正汉)
  • (Java入门)学生管理系统
  • (k8s)Kubernetes本地存储接入
  • (八)Flink Join 连接
  • (不用互三)AI绘画工具应该如何选择
  • (二)Kafka离线安装 - Zookeeper下载及安装
  • (附源码)springboot掌上博客系统 毕业设计063131
  • (接口自动化)Python3操作MySQL数据库
  • (数位dp) 算法竞赛入门到进阶 书本题集
  • (四十一)大数据实战——spark的yarn模式生产环境部署
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)为什么要选择C++
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (原创)可支持最大高度的NestedScrollView
  • (转)负载均衡,回话保持,cookie
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .net CHARTING图表控件下载地址
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .net知识和学习方法系列(二十一)CLR-枚举
  • .NET中的Exception处理(C#)
  • .skip() 和 .only() 的使用
  • []T 还是 []*T, 这是一个问题