JVM内存模型(JMM)是什么?如何理解happens-before关系?

详细说明JVM内存模型的概念,包括内存可见性、原子性、有序性,以及happens-before关系

参考答案

JVM内存模型(Java Memory Model)定义了Java程序中多线程访问共享内存的规则:

  1. JMM基本概念

目的

  • 屏蔽不同硬件和操作系统的内存访问差异
  • 让Java程序在各种平台上都能达到一致的内存访问效果
  • 保证多线程程序的正确性

核心问题

  • 内存可见性:一个线程对共享变量的修改,其他线程能否立即看到
  • 原子性:一个操作是否不可中断
  • 有序性:程序执行的顺序是否与代码顺序一致
  1. 主内存和工作内存

主内存(Main Memory)

  • 所有线程共享的内存区域
  • 存储所有变量的主本
  • 类似于物理机的RAM

工作内存(Working Memory)

  • 每个线程独有内存区域
  • 存储线程使用变量的副本
  • 类似于CPU的缓存

交互规则

  • 线程只能操作工作内存中的变量
  • 变量值在工作内存和主内存之间传递
  • 传递过程需要遵循特定规则
  1. 内存可见性问题

问题描述

public class VisibilityExample {
private boolean flag = false;

public void setFlag() {
flag = true;  // 线程A执行
}

public boolean getFlag() {
return flag;  // 线程B执行
}
}

问题分析

  • 线程A修改flag后,线程B可能看不到最新值
  • 原因:工作内存和主内存不同步
  • 结果:程序行为不可预测

解决方案

  • 使用volatile关键字
  • 使用synchronized关键字
  • 使用Lock接口
  • 使用Atomic类
  1. happens-before关系

定义

  • 如果操作A happens-before操作B,那么A的结果对B可见
  • 是JMM的核心概念
  • 用于判断操作的可见性

规则

  • 程序顺序规则:同一线程中的操作按程序顺序执行
  • 监视器锁规则:解锁操作happens-before后续的加锁操作
  • volatile变量规则:写操作happens-before后续的读操作
  • 线程启动规则:start()方法happens-before线程中的任何操作
  • 线程终止规则:线程中的任何操作happens-before线程终止
  • 中断规则:对线程interrupt()的调用happens-before被中断线程的代码检测到中断
  • 终结器规则:对象的构造函数happens-before对象的finalize()方法
  • 传递性:如果A happens-before B,B happens-before C,那么A happens-before C
  1. volatile关键字

作用

  • 保证变量的可见性
  • 禁止指令重排序
  • 不保证原子性

实现原理

  • 内存屏障:在读写操作前后插入内存屏障
  • 禁止重排序:编译器不会重排序volatile操作
  • 立即刷新:写操作后立即刷新到主内存

使用场景

public class VolatileExample {
private volatile boolean flag = false;

public void setFlag() {
flag = true;  // 立即对其他线程可见
}

public boolean getFlag() {
return flag;  // 总是读取最新值
}
}
  1. synchronized关键字

作用

  • 保证原子性:同一时刻只有一个线程执行
  • 保证可见性:解锁前将变量刷新到主内存
  • 保证有序性:禁止指令重排序

实现原理

  • 对象头:Mark Word存储锁信息
  • 监视器:每个对象关联一个监视器
  • 锁升级:偏向锁→轻量级锁→重量级锁

使用示例

public class SynchronizedExample {
private int count = 0;

public synchronized void increment() {
count++;  // 原子操作
}

public synchronized int getCount() {
return count;  // 可见性保证
}
}

评论区 (0)

暂无评论,来发表第一条评论吧!