2011-12-22 79 views
1

我有一个执行非常复杂的操作的对象的实例。如何使缓存线程安全

所以在第一种情况下我创建一个实例,并保存它,它自己的定制缓存。

从明年倍返还线程来,如果他发现有一个现成的对象已存在于他们把它从缓存中高速缓存,以便在性能良好的明智。

我很担心如果两个线程有​​什么相同的实例。这两个线程是否有可能互相腐蚀?

Map<String, SoftReference<CacheEntry<ClassA>>> AInstances= Collections.synchronizedMap(new HashMap<String, SoftReference<CacheEntry<ClassA>>>()); 
+0

缓存是否提交对其副本的引用,还是手抄送?线程如何将更改写入缓存对象?这些写入是否绕过缓存?如果是这样,是否从高速缓存弹出数据,因为高速缓存上的副本是陈旧的? – ArjunShankar 2011-12-22 15:09:30

+2

这将取决于您的缓存,请张贴您的代码。 – 2011-12-22 15:10:20

+0

它不依赖于实例的线程安全吗?你也可以同步访问你的缓存,并且只允许一个线程访问你的实例。 – 2011-12-22 15:12:07

回答

0

假设你正在谈论单身,只需使用“demand on initialization holder idiom”,以确保您的“检查”所有JVM的作品。这也将确保请求同一对象的所有线程并发地等待,直到初始化结束并且只返回有效的对象实例。

在这里,我假设你想要的对象的单个实例。如果没有,你可能想发布一些更多的代码。

0

有很多种可能的解决方案:

  • 使用像EHcache
  • 使用Spring框架,它有一个简单的方法来一个方法的缓存结果用一个简单的@Cacheable annotation
  • 使用一个现有的缓存解决方案提前像ConcurrentHashMap
  • 如果你知道所有的键同步地图,你可以使用一个lazy init code。请注意,此代码中的所有内容都是有原因的;在get()改变任何东西,它会打破最终(最终==“单元测试将运行,运行在生产一年不任何问题的任何后,将打破”)。

ConcurrentHashMap是最简单的设置,但它有简单的方式说“初始化键的值一次”。

不要试图自己实现缓存; Java中的多线程已成为Java 5以及多核CPU和内存障碍出现的一个非常复杂的领域。

[编辑]是的,这可能发生,即使地图是同步的。例如:

SoftReference<...> value = cache.get(key); 
if(value == null) { 
    value = computeNewValue(key); 
    cache.put(key, value); 
} 

如果两个线程同时运行这段代码,computeNewValue()会被调用两次。该方法调用get()put()是安全的 - 多个线程可以尝试把在同一时间并没有什么大不了的事情,但是这并不能保护你从中产生的,当你调用连续几种方法和的状态问题地图不得在它们之间改变。

0

好吧如果我正确理解你的问题,你担心的是2个对象改变共享对象会破坏彼此的状态。

简短的回答是肯定的,他们会的。

如果该对象在创建过程中很昂贵,但需要以只读方式。我建议你让它不可变,这样你就可以获得快速访问的好处,同时也是线程安全的。

如果状态应该可写,但实际上并不需要线程来查看其他每个更新。您只需将对象加载到不可变的缓存中,然后将副本返回给请求该对象的任何人。

最后,如果您的对象需要可写和共享(由于其他原因,而不是创建昂贵)。然后我的朋友你需要处理线程安全性,我不知道你的情况,但你应该看看synchronized关键字,Locks和Java 5并发特性,Atomic类型。我相信,他们中的一个将满足您的需求,我衷心祝愿你的情况是第2 :)