【高薪程序员必看】万字长文拆解Java并发编程!(5):深入理解JMM:Java内存模型的三大特性与volatile底层原理

简介: JMM,Java Memory Model,Java内存模型,定义了主内存,工作内存,确保Java在不同平台上的正确运行主内存Main Memory:所有线程共享的内存区域,所有的变量都存储在主存中工作内存Working Memory:每个线程拥有自己的工作内存,用于保存变量的副本.线程执行过程中先将主内存中的变量读到工作内存中,对变量进行操作之后再将变量写入主内存,jvm概念说明主内存所有线程共享的内存区域,存储原始变量(堆内存中的对象实例和静态变量)工作内存。


image.gif 编辑

Hello大家好!👋 我是摘星✨,今天给大家带来的是《深入理解JMM:Java内存模型的核心原理与高并发实战》的学习!🚀

在多线程编程中,你是否遇到过变量值莫名“消失”线程间数据不同步,甚至单例模式失效的诡异问题?💡 其实,这些问题的根源往往在于对 JMM(Java Memory Model,Java内存模型) 的理解不够深入!

在本篇内容中,我们将:

拆解JMM的核心概念——主内存 vs 工作内存,揭秘线程间数据交互的底层逻辑;

深度剖析JMM三大特性(原子性、可见性、有序性),并对比 volatilesynchronized 的适用场景;

通过经典单例模式,分析 volatile 如何用内存屏障解决指令重排序问题;

从JDK底层 解读 volatile写屏障读屏障机制,彻底搞懂它的可见性原理!

无论你是面试突击 🎯 还是高并发实战优化 ⚡,这篇文章都能让你对JMM的理解提升一个Level!📈 快跟着我一起探索吧! 🔍💻

目录

5. JMM

5.1. JMM内存定义

5.2. JMM特性

5.3. 可见性

5.4. 有序性

5.4.1. 指令重排

5.4.2. 禁止重排

5.4.3. 指令重排示例

5.5. volatile


5. JMM

5.1. JMM内存定义

JMM,Java Memory Model,Java内存模型,定义了主内存,工作内存,确保Java在不同平台上的正确运行

  • 主内存Main Memory:所有线程共享的内存区域,所有的变量都存储在主存中
  • 工作内存Working Memory:每个线程拥有自己的工作内存,用于保存变量的副本.线程执行过程中先将主内存中的变量读到工作内存中,对变量进行操作之后再将变量写入主内存,jvm

概念

说明

主内存

所有线程共享的内存区域,存储原始变量(堆内存中的对象实例和静态变量)

工作内存

每个线程私有的内存副本,存储线程操作所需的变量副本(栈内存中的局部变量和方法参数)

5.2. JMM特性

JMM的三大特性:

  • 原子性:确保操作的是不可分割的,一个线程执行一个原子操作时,其他线程无法同时执行对同一变量的操作,保证了指令不会受到线程上下文切换的影响
  • 可见性:当一个线程修改了共享变量的值后,其他线程能够立即看见修改后的变量值,保证指令不会受到CPU缓存的影响
  • 对于用volatile关键字修饰的变量,JMM保证了读操作和写操作的可见性
  • 对于没用volatile关键字修饰的变量,需要用到同步机制synchronized来保证变量的可见性
  • 有序性:程序的执行顺序必须符合开发者的预期,保证指令不会受到CPU指令并行优化的影响

特性

作用

实现方式

原子性

确保操作不可分割(如i++非原子,AtomicInteger原子)

synchronizedLockCAS(如AtomicInteger

可见性

线程修改后其他线程立即可见(解决CPU缓存不一致

volatilesynchronizedfinal(初始化后不可变)

有序性

防止指令重排序(如单例模式的双重检查锁volatile

volatile(内存屏障)、synchronized(代码块内有序)

5.3. 可见性

适用于只有一个线程修改变量值,有多个线程读取值的情况

volatile:用于修饰成员变量和静态变量,可以避免线程从自己的工作内存中查找变量的值,必须到主内存中获取变量的值,volatile操作的变量直接写到主内存中,这样就保证了线程之间的可见性,但是不能解决原子性

synchronized既可以解决线程之间的可见性问题,也可以解决原子性问题.但是synchronized操作更重量级,性能相对低

对比维度

volatile

synchronized

可见性

✅ 强制读写主内存

✅ 通过锁机制保证

原子性

❌ 不保证复合操作(如count+

✅ 保证代码块/方法内原子性

有序性

✅ 禁止指令重排序(内存屏障)

✅ 同步块内有序(as-if-serial语义)

性能

⚡ 轻量级(仅内存可见性)

⚠️ 重量级(线程阻塞/唤醒开销)

适用场景

状态标志(如boolean flag)、单例模式

多步骤复合操作(如转账

5.4. 有序性

5.4.1. 指令重排

指令重排:在不影响最终结果的前提下,对指令的执行顺序进行重排序和组合,达到指令并行的效果.

指令重排不能缩短单条指令的运行时间,但是可以变相的提高整个程序的吞吐率

5.4.2. 禁止重排

对变量加上volatile关键字可以保证该变量之前的变量不会被重排到自己的后面

5.4.3. 指令重排示例

// 无volatile时可能发生重排序,导致其他线程看到instance未初始化完成
class Singleton {
    private static volatile Singleton instance; // 需volatile禁止重排序
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton(); // 非原子操作(分配内存→初始化→赋值)
                }
            }
        }
        return instance;
    }
}

image.gif

5.5. volatile

volatile的底层实现原理是内存屏障Memory Barrier

volatile修饰的变量,会在其写指令之后加入写屏障,会在其读指令之前加入读屏障

写屏障:

  1. 保证本线程内的写指令前的指令不会重排序到其后,但是并不能保证读操作排到写屏障之前
  2. 保证写指令执行完毕后将变量值同步到主内存

读屏障:

  1. 保证读指令之后的共享变量全部从主内存中读取
  2. 保证读指令之后的指令不会排在读指令之前

volatile在JDK1.5之后才生效

屏障类型

作用

写屏障

1. 阻止屏障前的写操作重排到屏障后

2. 强制刷出工作内存到主内存(写操作后)

读屏障

1. 阻止屏障后的读操作重排到屏障前

2. 强制从主内存读取最新值(读操作前)

🎉 总结与展望

经过这篇的讲解,相信你已经对 JMM(Java内存模型) 有了更深入的理解!我们不仅剖析了 主内存与工作内存 的交互机制,还深入探讨了 原子性、可见性、有序性 这三大核心特性,并通过 volatilesynchronized 的对比,掌握了不同并发场景下的最佳实践。

🔹 关键回顾

  • **volatile** 适用于轻量级可见性控制(如状态标志、单例模式),但不保证原子性。
  • **synchronized** 能同时保证可见性+原子性,但性能开销较大,适合复杂同步场景(如转账操作)。
  • 指令重排序 虽然能优化性能,但在多线程环境下可能导致线程安全问题,而 volatile内存屏障机制可以有效禁止重排。

🔹 未来学习方向

如果你想进一步深入并发编程,可以研究:

CAS(Compare-And-Swap)Atomic 原子类

✅ **ThreadLocal 的内存泄漏问题**

✅ **ReentrantLocksynchronized 的性能对比**

🚀 实践出真知!建议你动手写几个多线程Demo,亲自体验 volatilesynchronized 的区别,这样才能真正掌握JMM的精髓!

💬 欢迎在评论区交流你的学习心得或遇到的并发问题,我们一起进步!下次见!👋

目录
相关文章
|
25天前
|
安全 Java 数据库连接
2025 年最新 Java 学习路线图含实操指南助你高效入门 Java 编程掌握核心技能
2025年最新Java学习路线图,涵盖基础环境搭建、核心特性(如密封类、虚拟线程)、模块化开发、响应式编程、主流框架(Spring Boot 3、Spring Security 6)、数据库操作(JPA + Hibernate 6)及微服务实战,助你掌握企业级开发技能。
196 3
|
1月前
|
Java
Java编程:理解while循环的使用
总结而言, 使用 while 迴圈可以有效解决需要多次重复操作直至特定條件被触发才停止執行任务场景下问题; 它简单、灵活、易于实现各种逻辑控制需求但同时也要注意防止因邏各错误导致無限迁璇発生及及時處理可能発生异常以确保程序稳定运作。
164 0
|
1月前
|
安全 Cloud Native Java
Java:历久弥新的企业级编程基石
Java:历久弥新的企业级编程基石
|
1月前
|
移动开发 Cloud Native Java
Java:历久弥新的企业级编程基石
Java:历久弥新的企业级编程基石
|
3月前
|
Java 数据库连接 API
2025 更新必看:Java 编程基础入门级超级完整版指南
本教程为2025更新版Java编程基础入门指南,涵盖开发环境搭建(SDKMAN!管理JDK、VS Code配置)、Java 17+新特性(文本块、Switch表达式增强、Record类)、面向对象编程(接口默认方法、抽象类与模板方法)、集合框架深度应用(Stream API高级操作、并发集合)、模式匹配与密封类等。还包括学生成绩管理系统实战项目,涉及Maven构建、Lombok简化代码、JDBC数据库操作及JavaFX界面开发。同时提供JUnit测试、日志框架使用技巧及进阶学习资源推荐,助你掌握Java核心技术并迈向高级开发。
390 5
|
10月前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
10月前
|
安全 Java 调度
Java中的多线程编程入门
【10月更文挑战第29天】在Java的世界中,多线程就像是一场精心编排的交响乐。每个线程都是乐团中的一个乐手,他们各自演奏着自己的部分,却又和谐地共同完成整场演出。本文将带你走进Java多线程的世界,让你从零基础到能够编写基本的多线程程序。
97 1
|
10月前
|
Java 数据处理 开发者
Java多线程编程的艺术:从入门到精通####
【10月更文挑战第21天】 本文将深入探讨Java多线程编程的核心概念,通过生动实例和实用技巧,引导读者从基础认知迈向高效并发编程的殿堂。我们将一起揭开线程管理的神秘面纱,掌握同步机制的精髓,并学习如何在实际项目中灵活运用这些知识,以提升应用性能与响应速度。 ####
119 3
|
11月前
|
Java
Java中的多线程编程:从入门到精通
本文将带你深入了解Java中的多线程编程。我们将从基础概念开始,逐步深入探讨线程的创建、启动、同步和通信等关键知识点。通过阅读本文,你将能够掌握Java多线程编程的基本技能,为进一步学习和应用打下坚实的基础。
|
算法 Java 开发者
Java 编程入门:从零到一的旅程
本文将带领读者开启Java编程之旅,从最基础的语法入手,逐步深入到面向对象的核心概念。通过实例代码演示,我们将一起探索如何定义类和对象、实现继承与多态,并解决常见的编程挑战。无论你是编程新手还是希望巩固基础的开发者,这篇文章都将为你提供有价值的指导和灵感。

热门文章

最新文章