专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java 内存模型(JMM)中的可见性、有序性、原子性

temp10 2025-07-19 22:31:21 java教程 1 ℃ 0 评论

可见性

  1. 什么是可见性

一个线程修改共享变量后,其他线程能立即看到修改后的值的能力。

  1. 为什么会存在可见性问题?
  • CPU 缓存架构:每个 CPU 核心有私有缓存(L1/L2),线程读写数据优先访问缓存而非主内存,修改后的数据不会立即同步到主内存或其他核心缓存
  • 编译器优化:编译器可能将频繁读取的变量缓存在寄存器,导致线程无法看到内存中的最新值
  1. 如何解决可见性问题?

volatile 机制:写操作后强制刷新数据到主内存。读操作前使本地缓存失效,从主内存重新加载。底层通过 StoreLoad 屏障实现(如 x86 的 LOCK 前缀指令)

Java 内存模型(JMM)中的可见性、有序性、原子性

public class VolatileTest {
    private static volatile boolean flag = false;
    public static void main(String[] args) throws InterruptedException {

        new Thread(() -> {
            System.out.println("waiting");
            while (!flag) {
                // do nothing
            }
            System.out.println("flag is true");
        }).start();

        Thread.sleep(2000);

        new Thread(VolatileTest::setFlag).start();

    }

    public static void setFlag() {
        System.out.println("set flag");
        flag = true;
        System.out.println("flag is set");
    }
}

有序性

  1. 什么是有序性?

程序执行的顺序符合代码编写的先后顺序。

  1. 为什么会存在有序性问题?
  • 编译器指令重排序,为优化性能调整无关指令顺序。
  • 处理器乱序执行,CPU 动态调整指令执行顺序以利用流水线。
  • 内存系统重排序,写缓冲区导致写操作延迟提交,失效队列导致缓存失效延迟处理。
  1. 如何解决有序性问题?

内存屏障禁止重排序volatile 写前插 StoreStore 屏障,写后插 StoreLoad 屏障,synchronized 退出时插入 StoreLoad 屏障

原子性

  1. 什么是原子性?

一个操作不可中断地完整执行,如同瞬时完成

  1. 为什么会存在原子性问题?

线程切换导致的指令交错。例如:

// i++ 的非原子操作
int i = 0;
i++ // 实际分三步:
     // 1. 读i到寄存器 (read)
     // 2. 寄存器+1     (add)
     // 3. 写回内存     (write)
  1. 如何解决原子性问题?

使用synchronized或者使用原子类

public class Add {

    int num = 0;

    public long getTotal() {
        return num;
    }

    public synchronized void add() {
        num++;
    }

}

使用原子类

public class AtomicAdd {

    private final AtomicInteger num = new AtomicInteger();

    public long getTotal() {
        return num.get();
    }

    public void add() {
        num.incrementAndGet();
    }
}



Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表