[英]Declaring object reference as volatile in Java?
我有一個看起來類似於以下內容的Spring bean類:
@Component
public class Foo{
private Config conf;
@PostConstruct
public void init(){
conf = ConfigFileLoader.loadConfigFromFile();
}
public Config getConfig(){
return conf;
}
public void updateConfig(){
conf = ConfigFileLoader.loadConfigFromFile();
}
}
ConfigFileLoader.loadConfigFromFile()從文件讀取配置,並返回一個新的Config對象。
有兩種類型的線程:
我的問題是,我應該將私有conf字段標記為volatile還是為conf字段添加某種同步?
我擔心的是以下情形:Updater線程更新conf引用,但更改永遠不會對讀取器線程可見。
任何幫助或解釋將不勝感激。
無論您使用volatile
還是采用@sibnick的建議並使用ReaderWriterLock,這里的危險是某些線程將長時間保留其自己的Config
對象私有引用:
Config myConfig = foo.getConfig();
while (conditionThatWillBeTrueForManyIterations()) {
doSomethingWith(myConfig);
}
這是不可能的編寫代碼,將未持續的時間,因為無論你用做一段時間自己的私人參考Config
的對象,你會互斥之外做。
即使你只寫這個:
doSomethingWith(foo.getConfig());
其他一些線程可能會在foo.getConfig()
調用與doSomethingWith(...)
調用之間更新配置。
您的程序必須能夠應對這種可能性。
易失性=嘗試使其他線程看到對象狀態的更新值,不保證線程同步運行,並且不保證它們不會進入破壞他人線程工作的情況
通過內部鎖進行的同步代碼=嘗試確保線程看到更新的對象狀態+保證線程同步工作並互相等待,以防止相互干擾。
您在此處定義的裝入方法將具有非原子的指令集。它將讀取文件並更新要裝入的對象。
必須單次完成從單個線程進行的讀取和更新操作,而不會受到其他線程的干擾,並嘗試重做相同的操作。
不確定性不是解決問題的可靠方法,因為您的操作不是一個單一的聲明/分配過程。
建議使用:對象上的固有鎖,並使讀取和更新方法同步運行。
public class Foo{
private Config conf;
Object lock = new Object();
@PostConstruct
public void init(){
synchronize(lock)
{
conf = ConfigFileLoader.loadConfigFromFile();
}
}
public Config getConfig(){
synchronize(lock)
{
return conf;
}
}
public void updateConfig(){
synchronize(lock)
{
conf = ConfigFileLoader.loadConfigFromFile();
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.