【问题标题】:Potential use for SoftReference with value (equals) equality具有值(等于)相等性的 SoftReference 的潜在用途
【发布时间】:2010-02-12 07:12:55
【问题描述】:

我之前得出的结论是,如果您需要一个具有基于值(等于)的相等性的软引用,那么除了内部人员之外,您的设计很糟糕。这是在 Google Collections 和 Guava 之后,不包括此类。但我遇到了一个我认为可以使用这样一个对象的问题。

我们在视觉效果渲染农场中有一个资产管理系统,其中有 100 个进程运行相同的作业,只是渲染的帧数不同。我们有一个 Oracle 数据库,需要记录所有使用的资产。在中间层资产管理系统中,我们可以使用 HashSet 来记录是否将插入 Oracle 的对象。

我可以使用具有过期时间的 Google MapMaker,但我不想担心过期时间是否正确,我们的渲染可以在数小时内运行,有时甚至需要几天时间。使用具有相等相等性的 SoftReference 听起来是一种更好的方法,因此 JVM 将自动管理垃圾收集。

对于我想使用带有垃圾收集的 ConcurrentHashMap 解决的其他问题,我将使用 HashMap 中的强引用作为获取 equals() 相等性的关键,并将 SoftReference 作为值,以便 JVM 可以垃圾收集某些东西,但在这种情况下,值无关紧要,我没有值可以包装在 SoftReference 中以放置在那里。所以似乎使用带有 equals() 的 SoftReference 就可以了。

对此有何其他建议?

【问题讨论】:

  • 喜欢你的问题,我最近也一直在想这个问题
  • ResourceBundle 不这样做吗?
  • @nanda 添加到 Oracle 的是动态生成的资产列表(比如 NFS 服务器上的文件名); ResourceBundle 似乎并不合适。我只需要一个 HashSet 来记录文件名已记录在 Oracle 中,因此另外 99 次尝试插入它不会浪费 Oracle 中的 CPU 周期。
  • 既然这东西真的很复杂,我真的可以从更多细节中受益:你的密钥类型是什么?什么是值类型?这些类型大约是什么样的?您想要软键、软值还是两者兼而有之,为什么?一旦MapMaker 支持尊重特定大小限制的其他驱逐策略(例如,LRU,尽管我们正在做的不完全是 LRU),您是否仍然需要此功能。如果可以存在多个相等的实例,为什么每当它们中的任何一个 one 被 GC 时清理一个条目是有意义的?另一个可能正处于被询问的边缘。
  • 输入Oracle的数据包括项目名称、文件夹路径、资产名称、版本号和表示名称。我有一个 POJO,RepLookupEntry,将它们作为字段。如果 HashSet 不包含 RepLookupEntry,则数据将进入 Oracle。由于我没有并发 HashSet,我将使用 ConcurrentHashMap。我需要软键,以便 GC 将它们逐出,但键必须使用 equals() 进行比较。我可以使用与 HashMap 值相同的 SoftReference,我没有其他东西可以放在那里。进程中的所有其他 RepLookupEntry 都是临时的,由客户端作为 RPC 创建。

标签: java concurrency guava concurrenthashmap


【解决方案1】:

在大多数情况下,当您想在 Google 收藏中使用软引用时,您应该调用

MapMaker.softValues()

对于强键但软值,查找将使用相等,并且当内存紧张时,键值对将被垃圾回收。

【讨论】:

  • 但是我没有与key关联的值,所以key是唯一可以放在软引用中的东西。
【解决方案2】:

由于没有ConcurrentHashSet使用软引用,所以只有两种方法:

1.) 您使用ConcurrentHashMap 的方法

  • 覆盖SoftReference 中的equalshashCode
  • equalshashCode 内部只能使用SoftReference#get 访问对象
  • SoftReference作为键,任何对象作为值(只允许null)
  • 如果引用在访问 hashCode 或 equals 时过时,请将引用添加到删除队列以频繁删除已失效的键。
  • 通过containsKey检查包含

2.) 使用 ConcurrentMultimap<Integer, Set<SoftReference<RepLookupEntry>> 并使用 hashCode 作为键,并使用一组同步的 SoftReferences 作为值。当您获得hashCode 命中时,请检查所有SoftReferences 的内容是否相等。不是很漂亮,我同意而且很难同步。

如果我处于你的位置,我根本不会使用 SoftReferences,而是使用 ConcurrentHashMap 来保持对你的 POJO 的强引用。每次有新元素到达时,也将其放入 ConcurrentLinkQueue。如果队列增长超过某个限制,则开始从 HashMap 中删除元素。

【讨论】:

    【解决方案3】:

    我认为这门课会满足你的需要:

    import java.util.*;
    import java.lang.ref.*;
    
    public class SoftSet<T> extends AbstractSet<T> {
    
      private final WeakHashMap<T,SoftReference<T>> data = new WeakHashMap<T,SoftReference<T>>();
    
      public boolean add(T t) {
        return null == data.put(t, new SoftReference<T>(t));
      }
    
      public boolean remove(Object o) {
        return null != data.remove(o);
      }
    
      public boolean contains(Object o) {
        return data.containsKey(o);
      }
    
      public Iterator<T> iterator() {
        return data.keySet().iterator();
      }
    
      public int size() {
        return data.size();
      }
    
      public void clear() {
        data.clear();
      }
    
      public boolean removeAll(Collection<?> c) {
        return data.keySet().removeAll(c);
      }
    
      public boolean retainAll(Collection<?> c) {
        return data.keySet().retainAll(c);
      }
    }
    

    这应该起作用的方式是,一旦作为值的软引用被清除,则该值仅是弱可访问的,并且可以从内部映射中删除键。

    【讨论】:

    • 可能是反对票,因为它将对象包装在两个单独的引用中,而不是它需要的。在 Google ConcurrentHashMap 中拥有一个具有 equals() 相等性的 SoftReference 子类可能会更简洁。
    猜你喜欢
    • 1970-01-01
    • 2019-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-19
    • 2013-12-30
    • 2010-10-12
    • 1970-01-01
    相关资源
    最近更新 更多