0

我不太确定该怎么做……所以我可能需要几次尝试才能正确回答这个问题。我有一个用于缓存方法结果的注释。我的代码现在是一个私有分支,但我正在处理的部分从这里开始: https ://code.google.com/p/cache4guice/source/browse/trunk/src/org/cache4guice/aop/CacheInterceptor .java#46

我已经注释了一个我想要缓存的方法,它运行一个非常慢的查询,有时需要几分钟才能运行。问题是,我的异步 Web 应用程序不断吸引新用户来询问相同的数据。但是,getSlowData() 方法尚未完成。

所以是这样的:

@Cached
public getSlowData() {
...
}

在拦截器内部,我们检查缓存并发现它没有被缓存,这将我们传递到:

return getResultAndCache(methodInvocation, cacheKey);

我从来没有对并发的整个概念感到满意。我认为我需要标记给定 getSlowData() 的 getResultAndCache() 方法已经启动,后续请求应该等待结果。

感谢您的任何想法或建议!

4

1 回答 1

2

大多数缓存实现会同步对“get”和“set”的调用,但这只是等式的一半。您真正需要做的是确保只有一个线程进入“检查是否已加载,如果不存在则加载”部分。在大多数情况下,序列化线程访问的成本可能不值得,如果有

 1) no risk 
 2) little cost

通过并行线程多次加载数据(如果您需要对此进行更多说明,请在此处评论)。由于此注解被普遍使用,我建议创建第二个注解,例如“@ThreadSafeCached”,invoke 方法将如下所示

    Object cacheElement = cache.get(cacheKey);
    if (cacheElement != null) {            
        LOG.debug("Returning element in cache: {}", cacheElement);            
    } else {
        synchronized(<something>) {
               // double-check locking, works in Java SE 5 and newer
           if ((cacheElement = cache.get(cacheKey)) == null) {
               // a second check to make sure a previous thread didn't load it
               cacheElement = getResultAndCache(methodInvocation, cacheKey);
           } else {
               LOG.debug("Returning element in cache: {}", cacheElement);            
           }
        }
    }
    return cacheElement;

现在,我留下了关于你同步的部分。最好锁定正在缓存的项目,因为您不会让任何未专门加载此缓存项目的线程等待。如果这不可能,另一种粗略的方法可能是锁定注释类本身。这显然效率较低,但如果您无法控制缓存加载逻辑(看起来像您一样),这是一个简单的出路!

于 2013-11-12T16:50:04.077 回答