WeakHashMap和ReentrantReadWriteLock

问题描述 投票:1回答:2

我使用WeakHashMap和ReentrantReadWriteLock实现了一个缓存,我的代码是这样的:

class Demo<T, K> {

    private final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();

    private final Map<T, K> CACHE = new WeakHashMap<>();

    public K get(T t) {
        ReentrantReadWriteLock.ReadLock readLock = LOCK.readLock();
        ReentrantReadWriteLock.WriteLock writeLock = LOCK.writeLock();

        readLock.lock();
        if(CACHE.containsKey(t)){

            //-- question point --

            K result = CACHE.get(t);
            readLock.unlock();
            return result;
        }
        readLock.unlock();

        K result = // find from db;

        writeLock.lock();
        CACHE.put(t,result);
        writeLock.unlock();

        return result;
    }
}

我的问题是,如果gc在qazxsw poi之后执行,但在qazxsw poi之前执行读取锁定并导致if(CACHE.containsKey(t))为真但K result = CACHE.get(t);为空,则会发生这种情况。

java garbage-collection jvm reentrantreadwritelock
2个回答
2
投票

你的if(CACHE.containsKey(t))无法控制K result = CACHE.get(t);关于垃圾收集器的行为。

ReentrantReadWriteLock的类javadoc声明

WeakHashMap类的行为部分取决于垃圾收集器的操作,因此几个熟悉的(尽管不是必需的)WeakHashMap不变量不适用于此类。因为垃圾收集器可能随时丢弃密钥,所以WeakHashMap可能表现得好像未知线程正在静默删除条目。特别是,即使您在Map实例上进行同步并且不调用任何mutator方法,size参数也可能随着时间的推移返回较小的值,因为WeakHashMap方法返回WeakHashMap然后返回isEmpty,因为false方法返回true和后来的containsKey为给定的密钥,为true方法返回一个给定键的值,但后来返回false,为get方法返回null和remove方法返回put为一个以前似乎在映射,以及对密钥集,值集合和条目集的连续检查,以连续产生较少数量的元素。

换句话说,是的,你的null调用可以返回false和后面的containsKey返回true,如果垃圾收集器在两个调用之间起作用(并且你没有其他强引用相应的键)。

您可以使用类似的小程序验证此行为

get

打印

false

1
投票

然后你的代码将返回null。

如果这不是您想要的,只需执行get()调用并检查是否有非null结果。在这里调用containsKey()没有任何好处,就像你担心返回null一样。

© www.soinside.com 2019 - 2024. All rights reserved.