我一直在阅读Java Concurrency in Practice一书。它绝对是一个很好的参考。我正在尝试扩展高效且可伸缩的结果集缓存的最后一个示例,以包含软引用。存储在我的缓存中的对象可能会变得相当大,我需要一些方法让这些对象在内存不足时收集垃圾,从而获得软引用。让线程安全和软的参考概念起作用已经测试了我的极限,我需要帮助。到目前为止,这是我的工作。我不确定这是否真的是线程安全的。有谁可以看一看并发表评论?
public class RelationCollectionCache {
// properties
private final ConcurrentMap<Integer, Reference<Future<RelationCollection>>> cache =
new ConcurrentHashMap<Integer, Reference<Future<RelationCollection>>>();
private final ReferenceQueue<? super Future<RelationCollection>> queue =
new ReferenceQueue<Future<RelationCollection>>();
// constructors
public RelationCollectionCache() {
}
// methods
public RelationCollection load(final Integer id) {
Reference<Future<RelationCollection>> reference = cache.get(id);
Future<RelationCollection> future = (reference == null) ? null : reference.get();
if (future == null) {
Callable<RelationCollection> eval = new Callable<RelationCollection>() {
public RelationCollection call() throws Exception {
return compute(id);
}
};
FutureTask<RelationCollection> task = new FutureTask<RelationCollection>(eval);
reference = cache.putIfAbsent(id, new InternalSoftReference(id, task));
if (((reference == null) ? null : reference.get()) == null) {
future = task;
task.run();
}
}
try {
return future.get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
private RelationCollection compute(Integer id) {
RelationCollection collection = new RelationCollection();
// lengthy computation of a large collection
return collection;
}
public RelationCollection get(Integer id) {
clean();
Reference<Future<RelationCollection>> reference = cache.get(id);
Future<RelationCollection> future = (reference == null) ? null : reference.get();
if (future == null)
return null;
try {
return future.get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
public void remove(Integer id) {
clean();
cache.remove(id);
}
public void clean() {
InternalSoftReference reference = (InternalSoftReference) queue.poll();
while (reference != null) {
cache.remove(reference.id);
reference = (InternalSoftReference) queue.poll();
}
}
// internal classes
private class InternalSoftReference extends SoftReference<Future<RelationCollection>> {
private Integer id;
public InternalSoftReference(Integer id, Future<RelationCollection> future) {
super(future, queue);
this.id = id;
}
}
}
此实现在每个操作中调用clean方法以清除垃圾收集的引用。这也可能是一个线程,但它包含了我甚至没有探索过的另一个并发级别。
答案 0 :(得分:3)
这非常困难。您可以使用MapMaker
中的google-collections吗?
答案 1 :(得分:1)
这是我的传球。我没有测试过这段代码,但我认为它可以捕获大部分案例
public class RelationCollectionCache {
// properties
private final ConcurrentMap<Integer, Reference<Future<RelationCollection>>> cache =
new ConcurrentHashMap<Integer, Reference<Future<RelationCollection>>>();
// constructors
public RelationCollectionCache() {
}
// methods
public RelationCollection load(final Integer id) {
Reference<Future<RelationCollection>> reference = cache.get(id);
Future<RelationCollection> future = (reference == null) ? null : reference.get();
while (future == null) {
final Callable<RelationCollection> eval = new Callable<RelationCollection>() {
public RelationCollection call() throws Exception {
return compute(id);
}
};
final FutureTask<RelationCollection> task = new FutureTask<RelationCollection>(eval);
final SoftReference<Future<RelationCollection>> newReference =
new SoftReference<Future<RelationCollection>>(task);
// Need to use replace as we may have an expired reference in the cache.
if (cache.replace(id, reference, newReference)) {
task.run();
future = task;
} else {
// Another thread may have done the replace
reference = cache.get(id);
future = (reference != null) ? reference.get() : null;
}
}
return getFromFuture(future);
}
private RelationCollection compute(final Integer id) {
final RelationCollection collection = new RelationCollection();
// lengthy computation of a large collection
return collection;
}
public RelationCollection get(final Integer id) {
Reference<Future<RelationCollection>> reference = cache.get(id);
if (reference == null) {
return null;
}
Future<RelationCollection> future = reference.get();
if (future == null) {
// Clean up the expired reference
while (!cache.remove(id, reference)) {
reference = cache.get(id);
future = (reference == null) ? null : reference.get();
// Its possible another thread may have replaced the
// expired reference with a valid in the mean time.
if (future != null) {
return getFromFuture(future);
}
}
return null;
}
return getFromFuture(future);
}
private static RelationCollection getFromFuture(final Future<RelationCollection> future) {
try {
return future.get();
} catch (final ExecutionException e) {
e.printStackTrace();
} catch (final InterruptedException e) {
e.printStackTrace();
}
return null;
}
public void remove(final Integer id) {
cache.remove(id);
}
}
我删除了干净的方法,因为在很多情况下它不起作用。对象不会总是转换为轻柔引用。对象可以直接强烈引用引用的幻像,因此不会出现在引用队列中。我将清理作为加载的一部分嵌入并进行操作。