2

在我的类的构造函数中,我将当前对象(this)连同它的键(在构造函数中作为参数输入的字符串)映射到静态 LinkedHashMap 中,这样我就可以在以后可能需要的任何地方通过字符串引用对象.

这是代码(如果有帮助):

public class DataEntry {
    /** Internal global list of DataEntry objects. */
    private static LinkedHashMap _INTERNAL_LIST;

    /** The data entry's name. */
    private String NAME;

    /** The value this data entry represents. */
    private Object VALUE;


    /** Defines a DataEntry object with a name and a value. */
    public DataEntry( String name, Object value )
    {
        if( _INTERNAL_LIST == null )
        {
            _INTERNAL_LIST = new LinkedHashMap();
        }

        _INTERNAL_LIST.put( name, this );

        NAME = name;
        VALUE = value;
    }
}

问题?当我使用完此类的实例时,它们不会被垃圾收集。

我只是好奇是否有办法让这个类的实例在我用完它们后自行清理,而不必每次都手动调用 Remove() 方法或其他东西(当我在内部 LinkedHashMap 中删除它的引用时) '不再使用它们,我的意思是)。

4

3 回答 3

6

改为使用值WeakReferences(或SoftReferences)。这样,这些值仍然可以被垃圾收集。当然,您仍然会在映射中包含条目 - 但您可以定期清除映射中 Weak/SoftReference 现在为空的任何条目。

于 2008-12-06T21:09:41.640 回答
5

在构造函数完成之前使对象对其他人可见不是线程安全的。

目前尚不清楚在这种情况下如何使用地图,但假设类中有这样的静态方法:

public static DataEntry getEntry(String name) {
  return _INTERNAL_LIST.get(name);
}

另一个并发运行的线程可以访问DataEntry它正在创建的一段时间,并开始使用一个未初始化的条目VALUE。即使您重新排序构造函数中的代码,以便将新实例添加到映射是您做的最后一件事,JVM 也可以重新排序指令,以便首先将对象添加到列表中。或者,如果类被扩展,子类初始化可以在对象发布之后进行。

如果多个线程访问与DataEntry类的交互,您可能会遇到一个依赖于平台、间歇性且很难诊断的并发错误。

Brian Goetz的文章“安全施工”提供了有关此主题的更多信息。

回到最初的问题:WeakReference正如其他人所提到的,使用 是一种很好的方法,但我建议不要为您的值创建一个扩展的包装器,而不是遍历地图中的每个条目WeakReference(它可以是您DataEntry自己,也可以是助手),并在 a 中对每个引用进行排队ReferenceQueue。这样,您可以快速轮询队列以获取任何收集的条目,并将它们从地图中删除。这可以通过在类初始化程序中启动的后台线程(阻塞 on )来完成,或者每次添加新条目时remove都可以清除(通过轮询)任何过时的条目。

如果你的程序是多线程的,你应该放弃LinkedHashMap一个 map from java.util.concurrent,或者包装LinkedHashMapwith Collections.synchronizedMap()

于 2008-12-06T22:06:21.243 回答
1

你想要使用的似乎是一个弱参考。这个概念是弱引用不足以强制对象不被 GC'ed。我对他们没有太多经验,但你可以在这里了解更多。

于 2008-12-06T21:03:37.423 回答