我對JVM內部知識的瞭解是,如果引用未正確發佈,則有可能不同線程會看到相同字段的不同值。Spring是否以線程安全的方式發佈bean?
我的問題是:春豆容器是否保證安全發佈?如果不是,我是否應該讓所有的我的豆獲得者和制定者或使用volatile
?或者也許使用final
字段和構造函數初始化?
我認爲這可能只是單身bean問題,因爲原型bean是根據請求線程按需創建的。我的理解是否正確?
我對JVM內部知識的瞭解是,如果引用未正確發佈,則有可能不同線程會看到相同字段的不同值。Spring是否以線程安全的方式發佈bean?
我的問題是:春豆容器是否保證安全發佈?如果不是,我是否應該讓所有的我的豆獲得者和制定者或使用volatile
?或者也許使用final
字段和構造函數初始化?
我認爲這可能只是單身bean問題,因爲原型bean是根據請求線程按需創建的。我的理解是否正確?
正如Evgeniy所述,應用程序上下文的初始化發生在單個線程中。因此,對你的問題的回答並不是與Spring的內部結構有關,而是創建上下文的線程與創建後使用上下文的線程之間的同步細節。
Java內存模型基於由各種規則定義的happens-before relation(Java語言規範,第17.4.5節)。例如,調用Thread.start
在一個線程中啓動一個新線程發生在之前的新啓動線程本身的所有操作。因此,如果您的應用程序的主線程首先創建應用程序上下文,然後啓動其他線程進行處理,那麼處理線程將保證能夠看到完全初始化的上下文。
字段標volatile
並處一之前發生關係,在這個意義上,如果線程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
}
}
這只是沒有必要。如果您擔心這一點,請將其自身的上下文標記爲不穩定。 – lscoughlin