在我的类的构造函数中,我将当前对象(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中删除它的引用时)我的意思是,我不再使用它们了.
改为使用WeakReferences(或SoftReferences)值.这样,值仍然可以被垃圾收集.当然,您仍然会在地图中有条目 - 但是您可以定期清除Weak/SoftReference现在为空的任何条目的地图.
在构造函数完成之前使其他对象可见是不是线程安全的.
目前还不清楚在这种情况下如何使用地图,但是假设在类中有这样的静态方法:
public static DataEntry getEntry(String name) { return _INTERNAL_LIST.get(name); }
另一个并发运行的线程可以访问DataEntry
它正在创建的时间,并开始使用未初始化的条目VALUE
.即使您对构造函数中的代码重新排序,以便将新实例添加到地图是您做的最后一件事,JVM也可以重新排序指令,以便首先将对象添加到列表中.或者,如果类被扩展,子类初始化可以在对象发布后进行.
如果多个线程访问与DataEntry
类的交互,则可能存在并发错误,该错误与平台相关,间歇性且非常难以诊断.
Brian Goetz 的文章"安全建构"提供了有关该主题的更多信息.
回到最初的问题:WeakReference
正如其他人所提到的,使用是一种很好的方法,但是我不建议迭代地图中的每个条目,而是建议为你的值扩展创建一个包装器WeakReference
(它可能是你DataEntry
自己,或者是帮助者),并将每个引用排队ReferenceQueue
.这样,您可以快速轮询队列以查找任何收集的条目,并将其从地图中删除.这可以通过remove
在类初始化程序中启动的后台线程(阻塞)来完成,或者每次添加新条目时都可以清除(通过轮询)任何陈旧条目.
如果你的程序是多线程的,你应该放弃LinkedHashMap
从一个地图java.util.concurrent
,或包裹LinkedHashMap
用Collections.synchronizedMap()
.