在同步方法

时间:2017-09-22 05:49:57

标签: java multithreading

在下面的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);
  }
}

1 个答案:

答案 0 :(得分:0)

  

但它总是在普通(非同步)方法serve()中读取。

除了serve()直接访问conf字段外,这将是一个问题。但是它正在调用latestConf() synchronized,所以你很好。

如果您将conf字段设为volatile,则可以直接在serve()中访问该字段,而无需synchronized阻止。分配到this.conf将跨越写入内存屏障,从this.conf读取将跨越读取内存屏障,确保安全发布conf

但是,如果需要每次测试以查看配置是否需要更新,则需要synchronized块。另一个想法是分叉一个线程,该线程在需要时在后台更新配置,这样工作线程就可以获得配置,并且由于volatile,它将保证最新。 / p>

另外,正如@JBNizet也指出的那样,使Conf中的字段成为final始终是一个非常好的模式,因为它确保构造函数在结果出现之前完全初始化字段。如果您使用synchronizedvolatile进行每次访问,那么