当前位置: 首页 > 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修饰的变量的在代码最开始位置

http://www.lryc.cn/news/356331.html

相关文章:

  • 医院挂号就诊系统的设计与实现
  • SpringBoot整合RabbitMQ的快速使用教程
  • pytorch比较操作
  • 2024年4月—马克思主义基本原理概论真题及答案解析(上海自考)
  • 「Element-UI表头添加带Icon的提示信息」
  • 单细胞 10X 和seurat对象学习
  • Flutter 中的 Flex 小部件:全面指南
  • 统计每个活动的用户访问量,且每个用户仅统计一次
  • 基于SpringBoot的本科生考研率统计系统
  • JMeter正则表达式提取器和JSON提取器基础用法,小白必会!
  • 5-26作业
  • 2024.05.28学习记录
  • 撤销最近一次的提交,使用git revert 和 git reset的区别
  • MySQL详细安装、配置过程,多图,详解
  • 音视频学习规划
  • 代码随想录算法训练营第21天|● 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● 236. 二叉树的最近公共祖先
  • K8S中Prometheus+Grafana监控
  • 题解:CF1968F(Equal XOR Segments)
  • Python操作MySQL实战
  • 【Linux系统】进程间通信
  • 北大国际医院腹膜后纤维化课题组 多学科协作开辟治疗新径
  • 面试数据库八股文十问十答第七期
  • 【C++题解】1133. 字符串的反码
  • 【Python编程实战】基于Python语言实现学生信息管理系统
  • AI网络爬虫:批量爬取电视猫上面的《庆余年》分集剧情
  • md5强弱碰撞
  • 【Docker故障处理篇】运行容器报错“docker: failed to register layer...file exists.”解决方法
  • 小红书-社区搜索部 (NLP、CV算法实习生) 一面面经
  • 解读makefile中的.PHONY
  • linux配置防火墙端口