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

java多线程的内存可见性问题,volatile是干什么的?

引入

首先我们用一段代码引出我们的问题,什么是内存可见性问题?

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) {}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了,而这就是我们要讲的内存可见性问题。

产生原因

内存可见性问题是由编译器优化导致的,一个线程读取,一个线程修改,修改的值并没有被读取线程读到。

编译器,虽然声称优化操作,是能够保证逻辑不变,尤其是在多线程的程序中,编译器的判断可能出现失误可能导致编译器的优化,使优化后的逻辑,和优化前的逻辑出现细节上的偏差。

jvm不知道什么时候才会进行修改,而且它的值始终没变所以将读取内存优化成了读取寄存器,因为寄存器比内存快,而这就导致了它无法识别到内存的修改,导致了误判。所以说t1的读操作不是真正的读内存。

解决方案

sleep

通过sleep()可以让循环时间延长,让其不再优化load()操作(因为相对于整个循环优化的时间无足轻重)。

但是sleep()方法代价太大了,因此引用了volatile(易变的)关键字,既然你编译器无法判别要不要优化,我就手动判别,当它修饰某个关键字的时候,不会把它优化成读寄存器。

volatile

volatile 关键字的作用主要有如下两个:

  1. 保证内存可见性 :基于屏障指令实现,即当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。
  2. 保证有序性:禁止指令重排序。编译时 JVM 编译器遵循内存屏障的约束,运行时靠屏障指令组织指令顺序。

指令重排序:也是编译器优化的一种形式,调整代码运行的先后顺序,以得到提高性能的效果。指令重排序的大前提是逻辑不变,在多线程的环境下,这里的判定可能出现失误。

votaile是用来修饰变量的,当它修饰的时候jvm就不会对这个变量进行读寄存器的优化,而我们之前的问题就可以迎刃而解了~

 public volatile int flag = 0;

感谢各位的观看~如果对你有帮助的话留个关注再走吧

http://www.dtcms.com/a/146235.html

相关文章:

  • 基于Python(Django)+SQLite实现(Web)校园助手
  • Time to event :Kaplan-Meier曲线、Log Rank检验与Shiny R
  • 线上地图导航小程序源码介绍
  • django入门
  • 介绍XML
  • 蓝桥杯 18.分考场
  • 室外摄像头异常自检指南+视频监控系统EasyCVR视频质量诊断黑科技
  • 如何平衡质量与进度的矛盾
  • L1-105 珍惜生命 - java
  • 安卓逆向工程:从APK到内核的层级技术解析
  • 使用json_repair修复大模型的json输出错误
  • 深入探索Qt异步编程--从信号槽到Future
  • 图形编辑器基于Paper.js教程27:对图像描摹的功能实现,以及参数调整
  • GPT-4.1 开启智能时代新纪元
  • OSPF数据包及工作过程
  • PaginationInnerInterceptor使用(Mybatis-plus分页)
  • 基于遗传算法的智能组卷系统设计与实现(springboot+ssm+React+mysql)含万字详细文档
  • 【项目管理】成本类计算 笔记
  • 基于 DeepSeek大模型 开发AI应用的理论和实战书籍推荐,涵盖基础理论、模型架构、实战技巧及对比分析,并附表格总结
  • 在ARM Linux应用层下驱动MFRC522
  • vue项目中使用antvX6(可拖拽,vue3)
  • 【Vue】组件基础
  • 浙江大学 DeepSeek 公开课 第三季 第1期讲座 - 唐谈 研究员 (附PPT下载) | 突破信息差
  • 【Linux网络】构建UDP服务器与字典翻译系统
  • 基于LangChain与Neo4j构建企业关系图谱的金融风控实施方案,结合工商数据、供应链记录及舆情数据,实现隐性关联识别与动态风险评估
  • java 使用Caffeine实现本地缓存
  • 归一化对C4.5决策树无效的数学原理与实证分析
  • ios17 音频加载失败问题
  • 基础服务系列-Mac Ngrok 内网穿透
  • 如何在腾讯云Ubuntu服务器上部署Node.js项目