首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java:需要关于WeakHashMap的建议

Java:需要关于WeakHashMap的建议
EN

Stack Overflow用户
提问于 2010-12-05 02:02:47
回答 2查看 1.3K关注 0票数 3

我猜我是另一个试图用WeakHashMap创建某种缓存的人。我需要一些帮助。

我有一堆TrackData对象,它们包含有关音轨的信息。然后是Track对象,它们在内部保留了对TrackData的引用。多个曲目可以指向相同的TrackData。然后我有一个看起来像这样的TrackDataCache类:

代码语言:javascript
复制
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依赖项。

EN

回答 2

Stack Overflow用户

发布于 2010-12-05 17:51:20

我建议用SoftReferences替换WeakReferences

任何仅由WeakReference引用的对象都是垃圾收集器每一轮的目标。这意味着你的缓存可以被清除,即使它仍然有足够的空闲内存。

如果您将WeakReference替换为SoftReference,那么您将声明:仅当绝对没有可用内存可分配时才删除引用的对象。

java中没有现成的SoftHashMap实现。在芭乐中有一个很好的例子- MapMaker。在生产环境代码上使用这个经过良好测试和验证的代码是值得的,而不是提供您自己的绝对质量较低的实现。它还具有令人惊叹的“自清洁”机制:

  1. 您可以指定cache max size:当映射大小增长到接近最大值时,映射将驱逐不太可能再次使用的条目。例如,地图可能会逐出条目,因为该条目最近未使用或使用频率很高。
  2. 您可以使用expireAfterWriteexpireAfterAccess方法指定地图条目的过期时间。

我也发现你的缓存设计不是很方便。正如我从您的代码片段中了解到的那样,从一开始,您的Track就具有对其TrackData的强引用,并且您可以在这些情况下构建缓存。但是,从某个时刻起,您希望使用缓存来检索数据,因此必须以其他方式创建新的Track,因为从那时起,您希望使用缓存,而不是强引用。

不同的Tracks可以有相同的TrackData,所以我们不能使用Track作为键。所以,我会采用下一种方法:

  1. 引入了中间ids级别,使缓存基于具有软值的Map<Integer, TrackData>,并定义了自清理策略(基于Track --> TrackDataTrack --> Id (int)MapMaker);
  2. change关系)。缓存Id --> TrackData.
票数 2
EN

Stack Overflow用户

发布于 2010-12-05 02:30:02

许多Track实例可以共享TrackData。我们需要一个密钥系统,它不需要TrackData为几个Track获取相同的实例。

代码语言:javascript
复制
 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对象的构造总是作为读取文件的一部分发生,但是为了支持共享实例而丢弃了创建的实例,我会像这样建模:

代码语言:javascript
复制
 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,并且需要从文件中读回它,在这种情况下,第一个解决方案比第二个更好地建模。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4354973

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档