Java 具有值(等于)相等的SoftReference的潜在用途

Java 具有值(等于)相等的SoftReference的潜在用途,java,concurrency,guava,concurrenthashmap,Java,Concurrency,Guava,Concurrenthashmap,我之前得出的结论是,如果你需要一个基于值(equals)相等的软引用,那么除了一个实习生之外,其他人的设计都很糟糕。这是在Google Collections和Guava之后,不包括这样一个类。但我遇到了一个问题,我认为可以使用这样的对象 我们在VisualEffects渲染场中有一个资产管理系统,其中100个进程运行相同的作业,但渲染的帧数不同。我们有一个Oracle数据库,需要记录使用的所有资产。在中间层资产管理系统中,我们可以使用哈希集记录要插入到Oracle中的对象是否正确,而不是使用相

我之前得出的结论是,如果你需要一个基于值(equals)相等的软引用,那么除了一个实习生之外,其他人的设计都很糟糕。这是在Google Collections和Guava之后,不包括这样一个类。但我遇到了一个问题,我认为可以使用这样的对象

我们在VisualEffects渲染场中有一个资产管理系统,其中100个进程运行相同的作业,但渲染的帧数不同。我们有一个Oracle数据库,需要记录使用的所有资产。在中间层资产管理系统中,我们可以使用哈希集记录要插入到Oracle中的对象是否正确,而不是使用相同的插入来重击Oracle,因为所有作业中只有一个插入成功

我可以使用过期的Google MapMaker,但我不想担心过期是否正确,我们已经在数小时内完成了渲染,有些甚至超过数天。使用相等的SoftReference听起来是一种更好的方法,这样JVM将自动管理垃圾收集

对于我想用带有垃圾收集的ConcurrentHashMap解决的其他问题,我将使用HashMap中的强引用作为获得equals()相等的键,并使用SoftReference作为值,以便JVM可以垃圾收集一些东西,但在这种情况下,值并不重要,我也没有一个值可以包装在SoftReference中放在那里。因此,似乎将SoftReference与equals()一起使用就可以了


关于这方面还有其他建议吗?

在大多数情况下,当您想在Google Collections中使用软引用时,您应该致电

MapMaker.softValues()

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

我认为此类将满足您的需要:

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);
  }
}
import java.util.*;
导入java.lang.ref.*;
公共类软件集扩展了抽象集{
私有最终WeakHashMap数据=新WeakHashMap();
公共布尔加法(T){
returnnull==data.put(t,新的软引用(t));
}
公共布尔删除(对象o){
返回null!=数据。删除(o);
}
公共布尔包含(对象o){
返回数据。containsKey(o);
}
公共迭代器迭代器(){
返回data.keySet().iterator();
}
公共整数大小(){
返回data.size();
}
公共空间清除(){
data.clear();
}
公共布尔removeAll(集合c){
返回data.keySet().removeAll(c);
}
公共布尔保留(集合c){
返回data.keySet().retainal(c);
}
}

这种方法的工作原理是,一旦清除了作为值的软引用,则该值只能弱访问,并且可以从内部映射中删除该键。

由于没有使用软引用的
ConcurrentHashSet
,因此只有两种方法:

1.)您使用
ConcurrentHashMap的方法

  • 软参考
  • equals
    hashCode
    的内部,只能使用
    SoftReference#get
  • SoftReference
    作为键,将任何对象作为值(仅允许null)
  • 如果该引用在访问hashCode或equals时过时,请将该引用添加到删除队列中,以频繁删除已失效的密钥
  • 通过
    containsKey

2.)使用
ConcurrentMultimapLove你的问题,我一直在想最近
ResourceBundle
不是这样做的吗?@nanda添加到Oracle的是动态生成的资产列表(比如NFS服务器上的文件名);ResourceBundle似乎不太合适。我只需要一个哈希集来记录文件名是在Oracle中记录的,这样再尝试99次插入它就不会在Oracle中浪费CPU周期。由于这件事非常复杂,我可以从更多细节中受益:您的密钥类型是什么?什么是值类型?这些类型大致是什么样的?您想要软键、软值还是两者都要,为什么?如果
MapMaker
支持其他符合特定大小限制的驱逐策略(例如,LRU,尽管我们所做的并不完全是LRU),您是否仍然需要此功能。如果可以存在多个相等的实例,为什么每当其中任何一个实例得到GC'd时都要清理一个条目呢?另一个可能即将被查询。输入Oracle的数据包括项目名称、文件夹路径、资产名称、版本号和表示名称。我有一个POJO,RepLookupEntry,这些都是字段。如果哈希集不包含RepLookupEntry,则数据将进入Oracle。因为我没有并发哈希集,所以我会使用ConcurrentHashMap。我需要软键,以便GC将它们逐出,但这些键必须使用equals()进行比较。我可以使用与HashMap值相同的SoftReference,我没有其他东西可以放在那里。进程中的所有其他RepLookupEntry都是临时的,由客户端作为RPC创建。但我没有与键关联的值,因此键是唯一可以放入软引用中的对象。可能是向下投票,因为它将对象包装在两个独立的引用中,而不是它需要的引用中。在Google ConcurrentHashMap中使用一个等于()的SoftReference子类可能会更干净。