我猜我是另一个试图用WeakHashMap创建某种缓存的人。我需要一些帮助。
我有一堆TrackData对象,它们包含有关音轨的信息。然后是Track对象,它们在内部保留了对TrackData的引用。多个曲目可以指向相同的TrackData。然后我有一个看起来像这样的TrackDataCache类:
public class TrackDataCache {
private static TrackDataCache instance = new TrackDataCache();
public static TrackDataCache getInstance() {
return instance;
}
private WeakHashMap<TrackData, WeakReference<TrackData>> cache = new WeakHashMap<TrackData, WeakReference<TrackData>>();
public void cache(Track track) {
TrackData key = track.getTrackData();
WeakReference<TrackData> trackData = cache.get(key);
if (trackData == null) {
cache.put(key, new WeakReference<TrackData>(key));
} else {
track.setTrackData(trackData.get());
}
}
}因此,当我加载一个曲目时,我会调用TrackDataCache.cache(),如果它的曲目数据以前没有加载过,它就会被缓存或替换为缓存的副本,否则(TrackData会重写equals()方法来检查位置和子曲索引)。我想使用弱引用,这样当我删除轨迹时就不需要关心了。
我想问一下,在WeakHashMap中保留对键的弱引用是不是一种可行的做法,如果不是,我应该如何解决这个问题?我需要弱引用和恒定时间来检索缓存值。我在考虑复制WeakHashMap代码并公开getEntry()方法,这解决了这个问题,但这是一个非常糟糕的方法:
PS。我知道apache或google集合可能有类似的东西,但我真的不想添加2Mb依赖项。
发布于 2010-12-05 17:51:20
我建议用SoftReferences替换WeakReferences。
任何仅由WeakReference引用的对象都是垃圾收集器每一轮的目标。这意味着你的缓存可以被清除,即使它仍然有足够的空闲内存。
如果您将WeakReference替换为SoftReference,那么您将声明:仅当绝对没有可用内存可分配时才删除引用的对象。
java中没有现成的SoftHashMap实现。在芭乐中有一个很好的例子- MapMaker。在生产环境代码上使用这个经过良好测试和验证的代码是值得的,而不是提供您自己的绝对质量较低的实现。它还具有令人惊叹的“自清洁”机制:
expireAfterWrite和expireAfterAccess方法指定地图条目的过期时间。我也发现你的缓存设计不是很方便。正如我从您的代码片段中了解到的那样,从一开始,您的Track就具有对其TrackData的强引用,并且您可以在这些情况下构建缓存。但是,从某个时刻起,您希望使用缓存来检索数据,因此必须以其他方式创建新的Track,因为从那时起,您希望使用缓存,而不是强引用。
不同的Tracks可以有相同的TrackData,所以我们不能使用Track作为键。所以,我会采用下一种方法:
Map<Integer, TrackData>,并定义了自清理策略(基于Track --> TrackData到Track --> Id (int)的MapMaker);Id --> TrackData.发布于 2010-12-05 02:30:02
许多Track实例可以共享TrackData。我们需要一个密钥系统,它不需要TrackData为几个Track获取相同的实例。
public class Track [
@Override
public int hashcode() {
... make hashcode that will be the same for
... tracks sharing the same track data.
}
@Override
public boolean equals() {
... ensure that if A.hashcode == B.hashcode then A.equals(B)
}
}
public class TrackDataManager {
private WeakHashMap<Track,TrackData> cache = new WeakHashMap<Track,TrackData>();
public TrackData getTrackData(Track track) {
// Track.hashcode()/equals() ensures two tracks that
// share track data will get the same object back
TrackData data = cache.get(track);
if (data == null) {
data = constructDataFromTrackFile(track);
cache.put(track, data);
}
return data;
}
private TrackData constructDataFromTrackFile(Track track) {
... read data from file and create that object.
}
}如果TrackData对象的构造总是作为读取文件的一部分发生,但是为了支持共享实例而丢弃了创建的实例,我会像这样建模:
public class TrackData {
@Override
public int hashcode() {
... make hashcode that will be the same for same track data.
}
@Override
public boolean equals() {
... ensure that if A.hashcode == B.hashcode then A.equals(B)
}
}
public class TrackDataCache {
private WeakHashMap<Integer,TrackData> cache = new WeakHashMap<Integer,TrackData>();
public TrackData getTrackData(Track track) {
// cache contains shared TrackData instances, we may throw away
// the Track instance in favour of the shared one.
Integer key = track.getTrackData().hashcode();
TrackData data = cache.get(key);
if (data == null) {
cache.put(key, track.getTrackData());
data = track.getTrackData();
} else {
// ensure we're using the shared instance, not the local one.
// deliberate object reference comparison
if (data != track.getTrackData()) {
track.setTrackData(data);
}
}
return data;
}
}请注意,只要存在保持对TrackData的引用的Track对象,WeakHashMap就不会在这两个解决方案中的任何一个中执行任何操作。这可以通过在Track中创建WeakReference来解决-然而这也意味着你最终可能没有任何TrackData,并且需要从文件中读回它,在这种情况下,第一个解决方案比第二个更好地建模。
https://stackoverflow.com/questions/4354973
复制相似问题