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

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

一、JMM是啥?

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

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

二、三大核心问题

1. 可见性问题

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

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

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

2. 有序性问题

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

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

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

3. 原子性问题

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

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

三、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,你就能写出线程安全的高性能代码! 🔒➡️🚀

相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼4 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen4 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone4 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui