【发布时间】:2014-07-23 12:44:09
【问题描述】:
我有一个来自“java concurrency pratique”一书中的例子,他说可变和不可变的持有者对象提供了线程安全。但我不明白书中给出的例子。
代码如下:
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);
}
}
我明白了
关键字 volatile 确保归档缓存对所有线程可见。
OneValueCache 类是不可变的。但是我们可以改变变量缓存的引用。
但我不明白为什么类 VolatileCachedFactorizer 是线程安全的。
对于两个线程(线程A和线程B),如果线程A和线程B同时到达factors == null,那么两个线程A和B都会尝试创建OneValueCache。然后线程 A 到达 factors = factor(i),而线程 B 同时到达 cache = new OneValueCache(i, factors)。然后线程 A 会创建一个 OneValueCache 覆盖线程 B 创建的值(OneValueChange 是不可变的,但对变量缓存的引用可以更改)。
说明代码不是线程安全的。
谁能告诉我为什么这段代码被认为是线程安全的以及为什么我错了?
【问题讨论】:
-
请注意,这是一个玩具箱。大多数线程安全问题要复杂得多。
-
我也很困惑.. xD 但后来我意识到任务是只存储最后一个因素。就那么简单。如果同时计算两次或其他什么都没关系......
-
我不明白,为什么我无法解析因子(i)是java数学函数???
标签: java thread-safety immutability volatile java-memory-model