Java:需要有关WeakHashMap的建议

时间:2010-12-04 18:02:47

标签: java caching weakhashmap

我想我是另一个尝试使用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()方法以检查位置和子索引)。我想使用弱引用,以便在删除Tracks时不需要关心。

我想问一下,在WeakHashMap中保持对密钥的弱引用是否可行,如果没有,我该如何处理这个问题?我需要弱引用和持续时间检索缓存值。我正在考虑复制WeakHashMap代码并将getEntry()方法公开,这解决了问题,但它是如此糟糕的黑客:(

PS。我知道apache或google集合可能有这样的东西,但我真的不想添加2Mb依赖项。

2 个答案:

答案 0 :(得分:2)

我建议将WeakReferences替换为SoftReferences

仅由WeakReference引用的任何对象都是每轮垃圾收集器的目标。这意味着即使存在足够的可用内存,也可以清除缓存。

如果用WeakReference替换SoftReference,则说明:只有在绝对没有可分配的可用内存时才删除引用的对象。

java中没有现成的SoftHashMap实现。番石榴有一个很好的例子 - MapMaker。值得使用经过充分测试和验证的生产环境代码,而不是提供您自己的质量较低的实现。它还具有惊人的“自我清洁”机制:

  1. 您可以指定cache max size
      

    随着地图大小越来越接近   最大值,地图将逐出条目   不太可能再次使用。   例如,地图可能会逐出   因为尚未使用而进入   最近或经常。

  2.   
  3. 您可以使用expireAfterWriteexpireAfterAccess方法为地图条目指定到期时间。
  4.   

    我也发现你的缓存设计不太方便。据我所知,从您的代码段开始,您的Track开始强烈引用他们的TrackData,并在这些情况下构建缓存。但是从某些时刻开始,您希望使用缓存来检索数据,因此您必须以其他方式创建新的Track,因为从那个时刻开始想要使用缓存而不是强引用。

    不同的Tracks可以具有相同的TrackData,因此我们无法将Track用作关键字。所以,我会选择下一个方法:

    1. 介绍中间ID级别,并根据具有软值的Map<Integer, TrackData>和定义的自清洁策略(基于MapMaker)制作缓存;
    2. 将关系Track --> TrackData更改为Track --> Id (int)。缓存Id --> TrackData

答案 1 :(得分:1)

TrackData可以由Track的许多实例共享。我们需要一个不需要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对象的构造总是作为读取文件的一部分发生,但是创建的实例被抛弃而偏向于共享实例,我会像这样建模:< / p>

 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;

   }

 }

请注意,WeakHashMap只要有Track个对象保持对TrackData的引用,就不会在这两个解决方案中的任何一个中执行任何操作。这可以通过在WeakReference内设置Track来解决 - 但这也意味着您最终可能没有TrackData,并且需要从文件中读取它,在这种情况下,第一个解决方案比第二种模型更好。