这是建议的解决方案(我确实搜索了相同的 - 失败了)
public abstract class AsyncCache<T> {
/**
* an atomic int is used here only because stamped reference doesn't take a long,
* if it did the current thread could be used for the stamp.
*/
private AtomicInteger threadStamp = new AtomicInteger(1);
private AtomicStampedReference<T> reference = new AtomicStampedReference<T>(null, 0);
protected abstract T rebuild();
public void reset() {
reference.set(null, 0);
}
public T get() {
T obj = reference.getReference();
if (obj != null) return obj;
int threadID = threadStamp.incrementAndGet();
reference.compareAndSet(null, null, 0, threadID);
obj = rebuild();
reference.compareAndSet(null, obj, threadID, threadID);
return obj;
}
}
该过程应该很容易看到 - 资源仅在请求时构建,并通过调用reset来使其无效。
请求资源的第一个线程将其ID插入到标记的引用中,然后在生成后插入其资源版本,除非调用另一个重置。 在后续重置的情况下,第一个请求线程将返回资源的陈旧版本(是有效用例),并且在最新重置之后开始的一些请求将使用其结果填充该引用。
如果我错过了某些内容或者有更好的(更快的+更聪明的,优雅的)解决方案,请告诉我。 有一件事 - 没有故意处理MAX_INT - 不相信编程会活得足够长,但肯定很容易做到。
谢谢。
答案 0 :(得分:1)
这绝对不是异步,因为请求线程将阻塞,直到rebuild()方法完成。另一个问题 - 您不检查compareAndSet返回的值。我相信你需要这样的东西
if(reference.compareAndSet(null, null, 0, threadID)) { //if resource was already reseted - rebuild
reference.compareAndSet(null, obj, threadID, threadID);
obj = rebuild();
}
但是这种方法有另一个缺点 - 你必须多次重建条目(考虑到几个线程一次想要这个条目)。您可以使用该案例的未来任务(http://www.codercorp.com/blog/java/simple-concurrent-in-memory-cache-for-web-application-using-future.html)或使用{{3 }}