【问题标题】:Using volatile to publish immutable objects?使用 volatile 发布不可变对象?
【发布时间】:2017-03-26 20:27:16
【问题描述】:
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 concurrency in practice一书中的代码,我的问题专门在这段代码中,我们可以从OneValueCache中删除final关键字,仍然保持线程安全,对,我不知道为什么这些是final必须的关键字。

谢谢。

【问题讨论】:

  • 是的,理论上可以忽略final 关键字,但您不应该这样做。你可以参考 Java Concurrency in Practice 的第 3.4.2 章。正如段落所说,我们想要创建一个不可变的对象。尽管lastNumlastFactors 是私有属性,但只有编写此类的人需要记住不要更改它们,最好将它们声明为final。一方面,Java 阻止您为这些属性重新分配值。此外,如果有人阅读此代码,可能带有“此类是不可变的”的注释,则更容易理解代码。

标签: java concurrency


【解决方案1】:

在这种情况下没有必要,但是在没有“final”关键字的情况下进行推理有点复杂。 基本上我们试图解决两个并发问题:

1) “缓存”引用的可见性 - 在此处使用“易失性”解决。

2) OneValueCache 对象的状态一致性(安全发布)。如《Java Concurrency In Practice》一书中所述:

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

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

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

...

因此,如果您从 OneValueCache 中删除“最终”用法,那么您将使此类更像是一个有效的不可变类,至少从可见性的角度来看,因为“最终”具有内存可见性语义(有点类似于“易失性”)并发。 因此,现在不要忘记类的任何用法的对象状态一致性,而是强迫自己在使用它时始终考虑安全发布。

它也类似于“16.1.4 同步的捎带”一章中描述的内容,因为您将使用写/读 volatile 引用的发生之前来保证 OneValueCache 对象在之后的所有线程中处于一致状态那个工程。基本上它似乎只是在这种情况下对“安全发布”问题的不同解释。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-26
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多