yun*_*shi 7 java volatile immutability thread-safety java-memory-model
我从"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);
}
}
Run Code Online (Sandbox Code Playgroud)
我明白那个
关键字volatile确保所有线程都可以看到字段缓存.
OneValueCache类是不可变的.但我们可以更改变量缓存的引用.
但我无法理解为什么类VolatileCachedFactorizer是线程安全的.
对于两个线程(线程A和线程B),如果线程A和线程B同时到达factors == null,则两个线程A和B都将尝试创建OneValueCache.然后线程A在线程B factors = factor(i)同时到达时到达cache = new OneValueCache(i, factors).然后线程A将创建一个OneValueCache覆盖threadB创建的值(OneValueChange是不可变的,但可以更改对变量缓存的引用).
它表明代码不是线程安全的.
谁能告诉我为什么这段代码被认为是线程安全的,为什么我错了?
因此,两个线程计算因子(一个为 67,另一个为 89),然后将它们的结果存储到缓存变量中。设置变量的最后一个线程获胜。假设第一个线程是最后一个将其因子存储在缓存中的线程。因此,缓存包含 67 的因子。
如果后续执行请求 67 的因数,它将从缓存中获取它们(因为缓存不为空,并且包含 67 的因数)。如果它请求另一个数的因数,它不会从缓存中获取它们,因此会计算这些因数,并将它们存储在缓存中,希望接下来的请求会请求相同数的因数。
没有什么可以保证两个线程不会从相同的数字计算因子。此代码提供的唯一保证是,如果缓存当前包含所请求数字的因子,则将返回这些缓存的因子(而不是其他数字的因子,或由数据竞争导致的不一致数据)
| 归档时间: |
|
| 查看次数: |
746 次 |
| 最近记录: |