MST

星途 面试题库

面试题:Java中Java内存模型如何影响线程间共享变量的可见性

请阐述在Java内存模型下,线程对共享变量的读写操作是如何保证其他线程能及时看到更新的,以及volatile关键字在其中起到什么作用。
12.3万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

线程对共享变量读写操作保证可见性的原理

  1. 缓存一致性协议:在多核处理器环境下,每个处理器核心都有自己的高速缓存(L1、L2等)。当线程读取共享变量时,会先从主内存将变量读取到自己核心的高速缓存中。当线程对共享变量进行修改时,会先修改自己高速缓存中的副本,然后通过缓存一致性协议将修改同步回主内存。其他线程在读取共享变量时,会发现自己高速缓存中的副本失效,从而从主内存重新读取最新的值。
  2. Java内存模型的规定:Java内存模型(JMM)定义了线程和主内存之间的抽象关系。线程之间的共享变量存储在主内存中,每个线程都有自己的工作内存,工作内存中保存了该线程使用到的共享变量的副本。线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接操作主内存。当线程修改共享变量后,需要将修改后的值刷新到主内存,其他线程在使用共享变量前,需要从主内存重新读取最新的值。

volatile关键字的作用

  1. 保证可见性:当一个变量被声明为volatile时,线程对该变量的修改会立即刷新到主内存,并且其他线程对该变量的读取都会从主内存获取最新的值,从而保证了其他线程能及时看到更新。例如:
public class VolatileExample {
    private volatile int value;

    public void setValue(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

在上述代码中,当一个线程调用setValue方法修改value时,修改会立即刷新到主内存,其他线程调用getValue方法时能获取到最新的值。 2. 禁止指令重排序:在Java中,为了提高程序的执行效率,编译器和处理器会对指令进行重排序。但是重排序可能会导致程序在多线程环境下出现错误。volatile关键字可以禁止指令重排序,确保volatile变量的写操作在其之前的操作都执行完毕后才执行,并且volatile变量的读操作在其之后的操作都在读取到最新值之后才执行。例如:

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

在上述双重检查锁定实现单例模式的代码中,instance被声明为volatile,防止了指令重排序导致其他线程可能获取到一个未完全初始化的instance对象。