假设我有以下缓存实现,目的是将一些数据(在我的例子中是连接池)与另一个对象的最新状态/版本相关联:
public class Demo<V> {
private final Map<Integer, VAR<V>> cache = new ConcurrentHashMap<>();
private final ReferenceQueue<V> refq = new ReferenceQueue<>();
private final Function<Integer, V> factory;
public Demo(Function<Integer, V> factory) {
this.factory = factory;
}
public static void main(String[] args) throws Exception {
Demo<Object> demo = new Demo<>(id -> new Object());
Object data = demo.getCached(1, 0);
assert data != null;
WeakReference<Object> keyReference = new WeakReference<>(data);
data = null;
while (keyReference.get() != null) {
System.gc();
Thread.sleep(1_000);
}
}
public V getCached(int id, int version) {
assert version >= 0;
VAR<V> ref = cache.get(id);
V storedData = ref == null ? null : ref.get();
int storedVersion = storedData == null ? -1 : ref.getVersion();
if (storedData == null) {
cache.remove(id, ref);
}
if (storedVersion >= version) {
return storedData;
}
Supplier<VAR<V>> varFactory = () -> {
V data = factory.apply(id);
return new WeakVAR(data, id, version);
};
BiFunction<Integer, VAR<V>, VAR<V>> replaceFunction = (key, existing) -> {
V data = existing == null ? null : existing.get();
if (data == null) {
return varFactory.get();
}
if (existing.getVersion() >= version) {
return existing;
}
return varFactory.get();
};
Supplier<V> vFactory = () -> cache.compute(id, replaceFunction).get();
/*
V result;
while ((result = vFactory.get()) == null) {
// nop
}
return result;
*/
return vFactory.get();
}
interface VAR<V> {
int getVersion();
int getId();
V get();
}
class WeakVAR extends WeakReference<V>
implements VAR<V> {
private final int id;
private final int version;
public WeakVAR(V referent, int id, int version) {
super(referent, refq);
this.id = id;
this.version = version;
}
@Override
public int getVersion() {
return version;
}
@Override
public int getId() {
return id;
}
}
}
问题是:当取消引用从
public V getCached(int id, int version)
返回的WeakReference
时,Map#compute
方法是否有可能返回null?如果是这样,克服这个问题的最佳方法是什么?忙循环是一个合适的解决方案吗?