在下面的Service
课程中,Conf
对象会在synchronized
方法latestConf()
中创建并发布(忽略init()
,因为只有一个线)。
但它始终以普通(非同步)方法serve()
读取。
上述过程是否确保serve()
方法始终读取正确发布的Conf
对象?或者我还需要synchronize
serve()
方法吗?
public class Service
{
private Conf conf;
private static class Conf
{
private String s1, s2;
Conf(String s1, String s2)
{
this.s1 = s1;
this.s2 = s2;
}
// Getters for s1 and s2
}
// 1. Called only once
public void init()
{
this.conf = loadConf();
}
// 2. Called by multiple threads after init()
public void serve()
{
Conf latestConf = latestConf();
System.out.println(latestConf);
}
private synchronized Conf latestConf()
{
if (!needToReloadConfiguration())
return this.conf;
Conf latestConf = loadConf();
this.conf = latestConf;
return latestConf;
}
private boolean needToReloadConfiguration()
{
// check if configuration needs to be reloaded
}
private Conf loadConf()
{
String s1 = ...;
String s2 = ...;
return new Conf(s1, s2);
}
}
答案 0 :(得分:0)
但它总是在普通(非同步)方法serve()中读取。
除了serve()
直接访问conf
字段外,这将是一个问题。但是它正在调用latestConf()
synchronized
,所以你很好。
如果您将conf
字段设为volatile
,则可以直接在serve()
中访问该字段,而无需synchronized
阻止。分配到this.conf
将跨越写入内存屏障,从this.conf
读取将跨越读取内存屏障,确保安全发布conf
。
但是,如果需要每次测试以查看配置是否需要更新,则需要synchronized
块。另一个想法是分叉一个线程,该线程在需要时在后台更新配置,这样工作线程就可以获得配置,并且由于volatile
,它将保证最新。 / p>
另外,正如@JBNizet也指出的那样,使Conf
中的字段成为final
始终是一个非常好的模式,因为它确保构造函数在结果出现之前完全初始化字段。如果您使用synchronized
或volatile
进行每次访问,那么