首页 > 解决方案 > 如何等到 WeakHashMap 更新?

问题描述

除了固定超时之外,还有其他方法可以知道WeakHashMap在密钥变得弱可访问后何时更新其条目?

例如,这段代码使对键的强引用无效,除非添加超时,否则仍会打印条目在映射中。

    WeakHashMap<Integer, Integer> map = new WeakHashMap<>();
    Integer i = 1000;
    map.put(i, 1);
    System.out.println(map.size()); // prints 1
    i = null;
    System.gc();
    //Thread.sleep(0);
    System.out.println(map.size()); // without sleep prints 1, with sleep prints 0

有没有更优雅的方法可以知道 WeakReferences 何时完成更新?

标签: javagarbage-collectionweak-referencesweakhashmap

解决方案


我不认为有一个好的方法可以做到这一点。有几个问题:

  1. 从 中清除陈旧条目WeakHashMap是一种内部机制,它涉及ReferenceQueue实现私有的。您需要打破封装才能访问该queue字段。

    好的,这是可能的,但是理论上你会让你的代码特定于 Java 版本。

  2. WeakHashMap除了自身 之外,没有什么好的方法可以检查队列。ReferenceQueue只提供三个公共操作poll()remove()remove(time_out)。这些都会从队列中删除一个元素(如果有的话)。但是,如果除WeakHashMap删除元素之外的任何其他内容,该元素将不会被处理。

    这实际上意味着您无法在不“破坏”队列的情况下检测到队列中何时有东西。

    好的,所以你也可以打破抽象ReferenceQueue来访问它的head字段。

  3. 即使您执行上述操作,您仍然需要轮询该ReferenceQueue.head字段以检测队列何时变为非空并再次为空。

  4. 处理队列的代码WeakHashMap不会自发运行。(没有更干净的线程。)它实际上是getput某些size东西clearWeakHashMap. 详细信息可能因版本而异。

    这意味着您的代码试图检测的“事件”只会在您调用get. 因此,如果您只想get在删除条目后调用,则时间依赖项中有一个“循环”。


最后,不能保证调用System.gc()会立即(或根本)运行,或者它会检测到给定的不可访问对象是不可访问的1。即使它确实检测到这一点,也不能保证它WeakReference会及时被破坏。

所以你不应该通过可预测的地图清理来编写你的应用程序来依赖这些东西。(如果这个只是单元测试的真正用例,我认为这不值得花时间在这上面。sleep解决方法很好......假设它足够可靠。)

1 - 例如,如果对象已被使用并且System.gc()调用仅触发次要收集,则该对象不会被检测为不可访问。


推荐阅读