使对象的所有字段最终确定是否可以保证安全发布



我正在阅读"Java Concurrency in Practice"中的安全发布,需要帮助来理解这个示例。我知道这很简单,但看起来我太投入了,感到困惑。

public class VolatileCachedFactorizer 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);
        cache = new OneValueCache(i, factors);
    }
    encodeIntoResponse(resp, factors);
}
}
class OneValueCache {
private final BigInteger lastNumber;
private final BigInteger[] lastFactors;
public OneValueCache(BigInteger i,
                     BigInteger[] factors) {
    lastNumber  = i;
    lastFactors = Arrays.copyOf(factors, factors.length);
}
public BigInteger[] getFactors(BigInteger i) {
    if (lastNumber == null || !lastNumber.equals(i))
        return null;
    else
        return Arrays.copyOf(lastFactors, lastFactors.length);
}
}

上面是两个类,一个是VolatileCachedFactorizer,它是一个servlet,只会由容器初始化一次,每个请求都会调用服务方法来获取传递的数字因子。

现在,OneValueCache是一个不可变的对象,它将缓存缓存中的最新数字及其因子。现在,根据这本书,它已安全出版。

我的问题是,OneValueCache在VolatileCachedFactorizer中没有被声明为final,尽管它的所有字段都是final的。当OneValueCache的构造函数从服务方法执行时,以下情况是否可能 -lastNumber 将被正确初始化(因为它是最终的),但 lastFactors 不是,因为这两个语句都是原子的。那么,它是否有可能处于不正确的状态。如果OneValueCache在VolatileCachedFactorizer中被声明为final,那么JVM将保证它将被正确初始化。

谢谢

对您的特定问题的简短回答是否定的。但需要注意的是,OneValueCache 实例"cache"是在服务方法中创建的,并立即对所有其他线程可见,因为这是由于 volatile 关键字的特征而实现的。如果线程 A 写入易失变量,那么一旦完成,线程 B 将看到线程 A 在遇到易失变量时所做的所有更改。

对于易失

性,内存操作没有重新排序,一旦创建了对象,就可以立即读取它,因为易失性变量不会缓存在本地缓存中,其中它对另一个处理器上的其他线程不可见。

如果您的混淆是正确实例化的缓存对象,那么

是的,那么只有正确构造的不可变缓存对象对其他线程可见。

最新更新