使用volatile来发布不可变对象?

时间:2016-09-29 06:37:15

标签: java concurrency

public class VolatileCachedFactorizer extends GenericServlet implements Servlet {

  private volatile OneValueCache cache = new OneValueCache(null, null);

  public void service(ServletRequest req, ServletResponse resp) {
    BigInteger i = extractFromRequest(req);
    BigInteger[] factors = cache.getFactors(i);
    if (factors == null) {             
        factors = factor(i);  //----------> thread A
        cache = new OneValueCache(i, factors);  //---------> thread B
    }
    encodeIntoResponse(resp, factors);
  }   
 }

public class OneValueCache {

  private final BigInteger lastNum;
  private final BigInteger[] lastFactors;

  public OneValueCache(BigInteger i, BigInteger[] lastFactors){
    this.lastNum = i;
    this.lastFactors = lastFactors;
  }

  public BigInteger[] getFactors(BigInteger i){
    if(lastNum == null || !lastNum.equals(i))
        return null;
    else
        return Arrays.copyOf(lastFactors, lastFactors.length);
  }

}

这是Java并发实践中的代码,我的问题是在这段代码中具体说明,我们可以从OneValueCache中删除final关键字并仍然保留线程安全,对,我不知道为什么这些是最终的必要的关键字。

感谢。

1 个答案:

答案 0 :(得分:0)

在这种情况下没有必要,但是在没有" final"关键字。 基本上我们试图解决两个并发问题:

1)"缓存的可见性"参考 - 通过使用" volatile"这里。

2)OneValueCache对象的状态一致性(安全发布)。正如" Java Concurrency In Practice"书:

  

对象的发布要求取决于其可变性:

     
      
  • 可以通过任何机制发布不可变对象;

  •   
  • 必须安全发布有效的不可变对象;

  •   
     

...

所以,如果你删除" final"来自OneValueCache的用法然后你使这个类更像是一个有效的不可变类,至少从可见性的角度来看,因为" final"在并发下具有内存可见性语义(有点类似于" volatile")。 因此,现在不要忘记类的任何用法的对象状态一致性,而是强迫自己在使用它时总是考虑安全发布。

它也类似于章节" 16.1.4同步抄袭"中所描述的内容,因为您将使用写入/读取易失性引用之前发生的事件来保证OneValueCache对象处于一致状态施工后的所有线程。基本上它似乎只是对安全出版物的不同解释"在这种情况下的问题。