如何使缓存线程安全

时间:2011-12-22 15:05:37

标签: java multithreading caching

我有一个对象的实例,它执行非常复杂的操作。

所以在第一种情况下,我创建了一个实例并将其保存为我自己的自定义缓存。

从下一次出现任何线程时,如果他发现一个现成的对象已经存在于缓存中,他们就会从缓存中获取它,以便在性能方面做得很好。

我担心如果两个线程具有相同的实例会怎么样。这两个线程是否有可能互相腐败。

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

4 个答案:

答案 0 :(得分:0)

假设您正在讨论单身人士,只需使用“demand on initialization holder idiom”确保您的“检查”适用于所有JVM。这也将确保请求相同对象的所有线程同时等待,直到初始化结束并且仅返回有效对象实例。

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

答案 1 :(得分: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()是安全的 - 几个线程可以尝试同时放置并且不会发生任何坏事,但这并不能保护您免受在调用多个方法时出现的问题继承地图的状态不得在它们之间发生变化。

答案 2 :(得分:0)

确定如果我正确理解您的问题,您会担心更改共享对象状态的2个对象会相互损坏。

简短的回答是肯定的。

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

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

最后,如果您的对象需要可写和共享(出于其他原因而不仅仅是创建昂贵)。然后我的朋友你需要处理线程安全,我不知道你的情况,但你应该看看synchronized关键字,锁定和java 5并发功能,原子类型。我相信其中一个会满足您的需求,我真诚地希望您的案例是最早的2之一:)

答案 3 :(得分:0)

如果您只有一个Object实例,请快速查看:

Thread-safe cache of one object in java

其他明智的我不能推荐google guava library,特别是MapMaker类。