Spring是否以线程安全的方式发布bean?
问题内容:
我对JVM内部的了解是,如果引用未正确发布,则不同的线程有可能看到相同字段的不同值。
我的问题是: Spring beans容器可以保证安全发布吗?
如果没有,我应该使用我所有的豆吸气剂和装塞器synchronized
还是使用volatile
?还是使用final
字段和构造函数初始化?
我认为这可能只是单例bean的问题,因为原型bean是根据请求线程按需创建的。我的理解正确吗?
问题答案:
正如Evgeniy所说,应用程序上下文的初始化发生在单个线程中。因此,您问题的答案与Spring的内部无关,而与创建上下文的线程和创建上下文的线程或使用上下文的线程之间的同步细节有关。
Java内存模型基于由各种规则定义的事前 发生
关系
(Java语言规范,第17.4.5节)。例如,在新启动的线程本身中的所有动作
之前
,调用Thread.start
一个线程来启动新线程。因此,如果您的应用程序的主线程先创建一个应用程序上下文,然后启动其他线程进行处理,则可以保证处理线程看到完全初始化的上下文。
__
标记的字段volatile
还强加了 事前发生的
关系,在某种意义上,如果线程A向a写入一个值volatile
,则看到该写入结果的任何其他线程也可以保证看到线程A 在 执行易失性写入 之前
所做的任何其他操作。因此,如果初始化线程和处理线程之间没有任何显式同步,则以下模式足以确保安全性
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
}
}