Java7 WeakHashMap isEmpty () кажется неправильным - PullRequest
4 голосов
/ 28 марта 2019

Я пытаюсь использовать Java7 WeakHashMap и обнаружил, что его метод isEmpty () дает неверные результаты.

import java.util.Map;
import java.util.WeakHashMap;

public class Test
{

    public static void main(final String[] args)
    {
        final Map<String, Boolean> map = new WeakHashMap<>();

        String b = new String("B");
        map.put(b, true);
        b = null;

        System.gc();
        System.out.println(map.isEmpty());
        System.out.println(map.keySet().isEmpty());
        System.out.println(map);
    }

}

Фактический результат:

false

true

{}

То есть

map.isEmpty () и map.keySet (). IsEmpty () не согласованы.Может ли кто-нибудь помочь мне понять это?Большое спасибо.

Ответы [ 2 ]

7 голосов
/ 28 марта 2019

Вы должны прочитать Javadoc WeakHashMap:

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

Суть всего того, что эффекты, которые вы видели, полностью действительны.

2 голосов
/ 28 марта 2019

WeakHashMap :: isEmpty говорит:

... Этот результат является снимком и может не отражать необработанные записи которые будут удалены до следующей попытки доступа, потому что они не являются ссылка больше.

Таким образом, вы ожидаете, что isEmpty() вернет правильное значение после GC и после доступа. Этот код демонстрирует это:

public class Scratch1 {
    public static void main(final String[] args) {
        final Map<String, Boolean> map = new WeakHashMap<>();

        String b = new String("B");
        map.put(b, true);
        b = null;

        System.gc();

        // map not internally accessed at this point
        System.out.println(map.isEmpty());

        // let's access the Map's internals (and hopefully coerce
        // it into removing no-longer-referenced keys)
        System.out.println(map.keySet()
                              .isEmpty());

        // map HAS now been accessed
        System.out.println(map.isEmpty());
    }

}

Урожайность:

false
true
true
...