Java7 WeakHashMap isEmpty()似乎错误

时间:2019-03-28 19:53:15

标签: java weakhashmap

我正尝试使用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 个答案:

答案 0 :(得分:7)

您应该阅读WeakHashMap的Javadoc:

  

WeakHashMap类的行为部分取决于垃圾回收器的动作,因此,一些熟悉的(尽管不是必需的)Map不变量对此类不成立。因为垃圾回收器可以随时丢弃键,所以WeakHashMap的行为就像是未知线程正在静默删除条目。特别是,即使您在WeakHashMap实例上进行同步并且不调用其任何mutator方法,对于sizeisEmpty方法也有可能随着时间的推移返回较小的值。 }方法返回false,然后返回true ,对于containsKey方法返回给定密钥的true,然后返回false,对于get方法返回给定键的值,但随后返回nullput方法返回null,而remove方法返回{{ 1}},用于以前似乎在地图中的某个键,并对该键集,值集合和条目集进行连续检查,以得出依次减少的元素数量。

您所看到的效果的全部不足之处是完全有效的。

答案 1 :(得分:2)

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