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

02 | Java内存模型:看Java如何解决可见性和有序性问题

第一部分:并发理论基础

02 | Java内存模型:看Java如何解决可见性和有序性问题


文章目录

  • 第一部分:并发理论基础
    • 02 | Java内存模型:看Java如何解决可见性和有序性问题
      • 什么是 Java 内存模型?
      • 使用 volatile 的困惑
      • Happens-Before 规则
        • 1. 程序的顺序性规则
        • 2. volatile 变量规则
        • 3. 传递性
        • 4. 管程中锁的规则
        • 5. 线程 start() 规则
        • 6. 线程 join() 规则
      • 被我们忽视的 final
      • 总结
      • 课后思考

上一期我们讲到在并发场景中,因可见性、原子性、有序性导致的问题常常会违背我们的直觉,从而成为并发编程的 Bug 之源。
那我们就先来聊聊如何解决其中的可见性和有序性导致的问题,这也就引出来了今天的主角——Java 内存模型

什么是 Java 内存模型?

你已经知道,导致可见性的原因是缓存,导致有序性的原因是编译优化,那解决可见性、有序性最直接的办法就是禁用缓存和编译优化,但是这样问题虽然解决了,我们程序的性能可就堪忧了

合理的方案应该是按需禁用缓存以及编译优化。那么,如何做到“按需禁用”呢?所以,为了解决可见性和有序性问题,只需要提供给程序员按需禁用缓存和编译优化的方法即可。

Java 内存模型是个很复杂的规范,可以从不同的视角来解读,站在我们这些程序员的视角,本质上可以理解为,Java 内存模型规范了 JVM 如何提供按需禁用缓存和编译优化的方法。具体来说,这些方法包括 volatile、synchronized 和 final 三个关键字,以及六项 Happens-Before 规则,这也正是本期的重点内容

使用 volatile 的困惑

volatile关键字并不是 Java 语言的特产,古老的 C 语言里也有,它最原始的意义就是禁用 CPU 缓存

例如,我们声明一个 volatile 变量 volatile int x = 0,它表达的是:告诉编译器,对这个变量的读写,不能使用 CPU 缓存,必须从内存中读取或者写入。这个语义看上去相当明确,但是在实际使用的时候却会带来困惑。

例如下面的示例代码,假设线程 A 执行 writer() 方法,按照 volatile 语义,会把变量 “v=true” 写入内存;假设线程 B 执行 reader() 方法,同样按照 volatile 语义,线程 B 会从内存中读取变量 v,如果线程 B 看到 “v == true” 时,那么线程 B 看到的变量 x 是多少呢?

直觉上看,应该是 42,那实际应该是多少呢?这个要看 Java 的版本,如果在低于 1.5 版本上运行,x 可能是 42,也有可能是 0;如果在 1.5 以上的版本上运行,x 就是等于 42。

// 以下代码来源于【参考1】 class VolatileExample { int x = 0; volatile boolean v = false; public void writer() { x = 42; v = true; } public void reader() { if (v == true) { // 这里x会是多少呢? } } }

分析一下,为什么 1.5 以前的版本会出现 x = 0 的情况呢?我相信你一定想到了,变量 x 可能被 CPU 缓存而导致可见性问题。这个问题在 1.5 版本已经被圆满解决了。Java 内存模型在 1.5 版本对 volatile 语义进行了增强。怎么增强的呢?答案是一项 Happens-Before 规则。

Happens-Before 规则

Happens-Before 并不是说前面一个操作发生在后续操作的前

http://www.jsqmd.com/news/1022033/

相关文章:

  • DeepSeek模型API永久降价:成本优化与AI服务商业化新趋势
  • DNS超时机制深度解析:9527背后的5秒设计原理与工程实践
  • AI编程工具如何解决团队协作四大断点:审查、知识、规范与上下文
  • 5G HARRQ反馈智能判决:四维动态模型降低误判率
  • 自动编码器与流形学习的拓扑分析及应用
  • 计算机毕业设计之基于vue的共享汽车用户数据分析与可视化
  • Python斐波那契七种实现:从入门到高并发生产实践
  • 终极指南:如何让Direct3D 8经典游戏在现代Windows系统上完美运行
  • 多相机兼容驱动方案:统一接口设计、核心实现与工业级优化
  • 深度解析AzurLaneAutoScript:碧蓝航线全自动脚本架构设计与性能优化策略
  • 2020容器技术演进:从隔离机制到云原生操作系统
  • 27-Docker部署Django(上)-从2GB到180MB的镜像瘦身实战
  • Ubuntu终端效率革命:Terminator分屏工作流实战指南
  • Google与ChatGPT本质区别:索引世界vs生成对话
  • EUREKA:面向大模型能力边界的模块化评估框架
  • Pixtral 12B实战指南:开源多模态模型的工程落地与OpenAI协议兼容
  • DNS协议深度解析:从报文结构到DNSSEC实战
  • 终极BepInEx插件框架指南:如何轻松为Unity游戏创建模组
  • BOxCrete: A Bayesian Optimization Open-Source AI Model for Concrete Strength Forecasting and MixOpt
  • F★程序安全提取与关系引用技术解析
  • MPC8360E PowerQUICC II Pro寄存器配置实战:从架构到调试
  • 遗传算法解决医院排班难题:Python+DEAP实战指南
  • Ubuntu换源教程:用LinuxMirrors脚本一键切换国内镜像源
  • R语言数据结构本质:内存布局、类型契约与性能优化
  • 如何在Windows电脑上免费实现AirPlay投屏接收:完整开源方案指南
  • F★程序安全提取:形式化验证与IO操作处理
  • Kimi K2开源MoE大模型:1T参数与32B激活的工业级Agent基座
  • 2026年上海起诉小三返还转账实务测评:原配维权路径与律师资源深度分析 - 优质品牌商家
  • 百度文库文档获取实战指南:高效免费保存解决方案深度解析
  • AI大模型普通人实操指南:从理解原理到30分钟落地应用