Java7 的 WeakHashMap isEmpty() 方法似乎有误

4

我正在尝试使用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
从Java 8 API文档中关于WeakHashMap类的描述可以看出:“由于垃圾收集器可能随时丢弃键,因此WeakHashMap可能表现得好像未知线程正在静默地删除条目。”和“..随着时间的推移,size方法返回较小的值是有可能的,isEmpty方法返回false然后返回true..”,所以我认为没有必要担心。 - yegodm
1
请查看这个链接 - Leonardo Alves Machado
2个回答

7
你应该阅读 WeakHashMap 的 javadoc:

WeakHashMap 类的行为部分依赖垃圾收集器的操作,因此一些熟悉的(但不是必需的)Map 不变式对于该类来说不适用。由于垃圾收集器可能随时丢弃键,因此 WeakHashMap 可能会表现得好像一个未知的线程正在静默删除条目。特别地,即使在同步 WeakHashMap 实例并调用其 mutator 方法之一的情况下,它仍可能导致 size 方法随时间返回较小的值,导致 isEmpty 方法返回 false 然后返回 true,导致 containsKey 方法为给定的键返回 true,稍后返回 false,导致 get 方法为给定的键返回值,但稍后返回 null,导致 put 方法返回 null,而 remove 方法返回 false,以前似乎在映射中出现的键,以及对键集、值集和条目集的连续检查将产生逐渐减少的元素。

总之,你看到的效果是完全有效的。


1
根据Leonardo Alves Machado的评论:请查看什么是WeakHashMap?何时使用它? - Andreas

2

WeakHashMap::isEmpty的解释如下:

...该结果是一个快照,可能不反映未经处理的条目。在下一次尝试访问之前因为它们不再被引用而将被删除。

因此,您可以在GC后访问后期望isEmpty()返回正确的值。以下代码演示了这一点:

(原始答案:Original Answer)
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接