深入浅出Java内存模型(JMM)

深入浅出Java内存模型(JMM)

一、JMM是啥?

Java内存模型(JMM)就像多线程世界的交通规则

  • 作用:定义线程如何与内存交互,防止"数据车祸"
  • 核心问题 :解决多线程的可见性有序性原子性问题
  • 类比
    • 内存:共享的快递仓库
    • 线程:搬运工人
    • JMM规则:仓库的存取管理制度

二、三大核心问题

1. 可见性问题

java 复制代码
// 线程A
flag = true;  // 写操作

// 线程B
while(!flag); // 可能永远死循环!

问题 :线程A改了flag,线程B看不见
解决 :用volatilesynchronized

2. 有序性问题

java 复制代码
// 代码顺序
int a = 1;
int b = 2;

// 实际执行可能变成:
int b = 2;
int a = 1;

问题 :编译器/CPU会优化指令顺序(重排序)
解决 :用volatilefinal

3. 原子性问题

java 复制代码
count++; // 实际包含3步操作:读→改→写

问题 :多线程同时操作会导致数据错误
解决 :用synchronizedAtomicInteger

三、JMM关键概念

1. 主内存 vs 工作内存

graph LR 主内存 -->|读取| 线程A工作内存 主内存 -->|读取| 线程B工作内存 线程A工作内存 -->|写入| 主内存 线程B工作内存 -->|写入| 主内存
  • 主内存:所有线程共享(相当于仓库)
  • 工作内存:每个线程私有(相当于工人的手推车)

2. happens-before原则(重点!)

JMM规定的操作先后保证规则

  1. 程序顺序规则:同一线程内,代码顺序优先
  2. 锁规则:解锁操作先于后续加锁操作
  3. volatile规则:写操作先于后续读操作
  4. 传递性:A先于B,B先于C → A先于C

示例

java 复制代码
// 线程A
x = 1;          // 操作1
volatileFlag = true; // 操作2(volatile写)

// 线程B
if(volatileFlag) {   // 操作3(volatile读)
    print(x);    // 保证看到x=1!
}

四、volatile关键字

1. 两大特性

  • 可见性:写操作立即刷新到主内存
  • 禁止重排序:优化屏障

2. 底层实现

java 复制代码
// Java代码
volatile boolean flag = false;

// 对应汇编指令(带lock前缀)
0x01a3de24: lock addl $0x0,(%esp);

3. 使用场景

  • 状态标志位(如volatile boolean running
  • 单例模式双重检查锁定
java 复制代码
class Singleton {
    private static volatile Singleton instance;
    
    static Singleton getInstance() {
        if (instance == null) {
            synchronized(Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

五、synchronized机制

1. 内存语义

  • 进入同步块:清空工作内存,从主内存重新加载
  • 退出同步块:将工作内存写回主内存

2. 锁升级过程

graph LR 无锁 --> 偏向锁 --> 轻量级锁 --> 重量级锁
  • 偏向锁:只有一个线程访问时生效
  • 轻量级锁:少量线程竞争时用CAS自旋
  • 重量级锁:真正调用操作系统互斥量

六、final的内存语义

1. 特殊规则

  • 构造函数内:正确初始化的final字段,对其他线程立即可见
  • 禁止重排序:防止构造函数未完成就暴露对象引用

2. 安全发布示例

java 复制代码
class FinalExample {
    final int x;
    static FinalExample instance;
    
    public FinalExample() {
        x = 42; // final写
    }
    
    static void writer() {
        instance = new FinalExample(); // 安全发布
    }
    
    static void reader() {
        if (instance != null) {
            System.out.println(instance.x); // 保证看到x=42
        }
    }
}

七、JMM与硬件关系

Java概念 硬件对应
主内存 RAM内存
工作内存 CPU缓存/寄存器
内存屏障 CPU内存屏障指令
volatile lock指令+CACHE一致性协议

八、常见误区

1. volatile ≠ 原子性

java 复制代码
volatile int count = 0;
count++; // 仍然不是原子操作!

2. synchronized性能差?

  • 现代JVM已大幅优化(偏向锁/自适应自旋)
  • 竞争不激烈时开销很小

3. final只在编译期有效?

  • 运行期仍有内存语义保证

九、终极口诀

"JMM管线程内存,三大问题要记牢

可见有序加原子,volatile能解前两样

锁住同步最保险,happens-before是准绳

内存屏障底层撑,多线程安全有保障"

理解JMM,你就能写出线程安全的高性能代码! 🔒➡️🚀

相关推荐
___波子 Pro Max.34 分钟前
Android envsetup与Python venv使用指南
android·python
武帝为此1 小时前
【MySQL 删除数据详解】
android·数据库·mysql
顾林海1 小时前
深度解析HashMap工作原理
android·java·面试
V少年2 小时前
深入浅出DiskLruCache原理
android
鱼洗竹2 小时前
协程的挂起与恢复
android
清风~徐~来3 小时前
【Linux】进程创建、进程终止、进程等待
android·linux·运维
百锦再4 小时前
Android游戏辅助工具开发详解
android·游戏·模拟·识别·辅助·外挂
QING6184 小时前
Kotlin 类型转换与超类 Any 详解
android·kotlin·app
QING6184 小时前
一文带你了解 Kotlin infix 函数的基本用法和使用场景
android·kotlin·app
张风捷特烈5 小时前
平面上的三维空间#04 | 万物之母 - 三角形
android·flutter·canvas