Spring是否以线程安全的方式发布豆类?

2022-09-02 22:15:31

我对 JVM 内部的了解是,如果引用未正确发布,则不同的线程可能会看到相同字段的不同值。

我的问题是:豆子容器能保证安全发布吗?如果没有,我应该做我所有的bean getters和setters还是使用?或者也许使用字段和构造函数初始化?synchronizedvolatilefinal

我假设这可能只是单例bean的问题,因为原型bean是根据请求线程按需创建的。我的理解是否正确?


答案 1

正如Evgeniy所说,应用程序上下文的初始化发生在单个线程中。因此,您的问题的答案与其说与Spring的内部结构有关,不如说是创建上下文的线程与创建上下文后使用上下文的线程之间的同步细节。

Java 内存模型基于由各种规则定义的先发生关系(Java 语言规范,§17.4.5)。例如,在一个线程中启动新线程的调用发生在新启动线程本身中的所有操作之前。因此,如果应用程序的主线程首先创建应用程序上下文,然后启动其他线程进行处理,则保证处理线程能够看到完全初始化的上下文。Thread.start

标记的字段还强制施加了一个发生之前的关系,因为如果线程 A 将值写入 a ,则看到该写入结果的任何其他线程也保证看到线程 A 在执行易失性写入之前执行的任何其他操作。因此,如果初始化线程和处理线程之间没有任何显式同步,则以下模式足以确保安全性volatilevolatile

public class Setup {
  private volatile boolean inited = false;

  private ApplicationContext ctx;

  public boolean isInited() { return inited; }

  public ApplicationContext getContext() { return ctx; }

  public void init() {
    ctx = new ClassPathXmlApplicationContext("context.xml");
    inited = true; // volatile write
  }
}

public class Processor {
  private void ensureInit() {
    while(!setup.isInited()) { // volatile read
      Thread.sleep(1000);
    }
  }

  public void doStuff() {
    ensureInit();
    // at this point we know the context is fully initialized
  }
}

答案 2