《Java 并发编程实战》P40的疑惑

2019-03-03  本文已影响0人  nicaima

一、问题

@Immutable
public class OneValueCache {

    // final
    private final BigInteger lastNumber;
    private final BigInteger[] lastFactors;

    // Arrays.copyOf
    public OneValueCache(BigInteger lastNumber, BigInteger[] lastFactors) {
        this.lastNumber = lastNumber;
        this.lastFactors = Arrays.copyOf(lastFactors, lastFactors.length);
    }

    // Arrays.copyOf
    public BigInteger[] getFactors(BigInteger i) {
        if (lastNumber == null || !lastNumber.equals(i)) {
            return null;
        } else {
            return Arrays.copyOf(lastFactors, lastFactors.length);
        }
    }
}

@ThreadSafe
public class VolatileCacheFactorizer {

    private volatile OneValueCache cache = new OneValueCache(null, null);

    /**
     * 疑问:有没有可能一个线程在cache.getFactors(i)时,判断相等要取值时,
     * 另一个线程new新的OneValueCache。
     *
     * 《Java 并发编程实战》P40原文:如果是一个不可变对象,那么当线程
     *  获得了对该对象的引用后,就不必担心另一个线程会修改对象的状态。
     *
     */
    public void service(Request request, Response response) {
        BigInteger i = extractFromRequest(request);
        BigInteger[] factors = cache.getFactors(i);
        if (factors == null) {
            factors = factor(i);
            cache = new OneValueCache(i, factors);
        }
        encodeIntoResponse(response, factors);
    }
}

疑问点:有没有可能一个线程在cache.getFactors(i)时,判断相等要取值时,另一个线程new新的OneValueCache。

二、解惑

注意当线程A执行cache.getFactors(i)时,如果判断了可以取这个缓存,那么此时这个cache对象就是安全的,因为另一个线程B是new的新的OneValueCache对象,线程A在执行cache.getFactors(i)时,老的OneValueCache对象并没有被GC掉。所以是线程安全的。当线程B执行完时,其他对象通过volatile看到新的cache。

通过使用包含多个状态变量的容器对象来维持不变性条件,并使用一个volatile类型的引用来确保可见性,使得VolatileCachedFactorizer在没有显式地使用锁的情况下仍然是线程安全的。

上一篇下一篇

猜你喜欢

热点阅读