使所有字段最终成为对象可以保证安全发布吗?

时间:2014-11-27 04:29:46

标签: java multithreading

我正在阅读“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,只能由容器初始化一次,每个请求都会调用service方法来获取传递的数字因子。

现在,OneValueCache是​​一个不可变对象,它会缓存缓存中的最新数字及其因素。 现在,按照这本书安全发布。

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

由于

1 个答案:

答案 0 :(得分:0)

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

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

如果你的混淆是在正确实例化的缓存对象上然后是,那么只有正确构造的不可变缓存对象才能对其他线程可见。