WeakHashMap и ReentrantReadWriteLock - PullRequest
       49

WeakHashMap и ReentrantReadWriteLock

1 голос
/ 09 апреля 2019

Я реализовал кеш с использованием 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 исполняется после if(CACHE.containsKey(t)), но до K result = CACHE.get(t); с блокировкой чтения и приводит к тому, что if(CACHE.containsKey(t)) верно, но K result = CACHE.get(t); становится нулевым.

Ответы [ 2 ]

2 голосов
/ 09 апреля 2019

Ваш ReentrantReadWriteLock не контролирует поведение WeakHashMap в отношении сборщика мусора.

Класс javadoc для WeakHashMap состояний

Поведение класса WeakHashMap частично зависит от действий сборщика мусора, поэтому несколько знакомых (хотя и не обязательных) инвариантов Map для этого класса не выполняются.Поскольку сборщик мусора может отбрасывать ключи в любое время, WeakHashMap может вести себя так, как будто неизвестный поток молча удаляет записи.В частности, даже если вы синхронизируете экземпляр WeakHashMap и не вызываете ни один из его методов-мутаторов, метод size может возвращать меньшие значения с течением времени, а метод isEmpty возвращает false, а затем true, для метода containsKey для возврата true и позже false для данного ключа , для метода get для возврата значения для данного ключа, но позднее для возврата null,для метода put для возврата null и метода удаления для возврата false для ключа, который ранее казался на карте, и для последовательных проверок набора ключей, сбора значений и записи, установленной навыдает последовательно меньшее число элементов.

Другими словами, да, ваш containsKey вызов может вернуть true и get, который следует для возврата false, еслисборщик мусора действует между двумя вызовами (и у вас нет других сильных ссылок на соответствующий ключ).

Такое поведение можно проверить с помощью небольшой программы, такой как

* 10.38 *

который печатает

missing? null
1 голос
/ 09 апреля 2019

Тогда ваш код вернет ноль.

Если это не то, что вам нужно, просто вызовите get () и проверьте, что вы получили ненулевой результат.Здесь нет никакого смысла в вызове containsKey (), как вы делаете, если вы беспокоитесь о возврате null.

...