【问题标题】:How to make cache thread safe如何使缓存线程安全
【发布时间】:2011-12-22 15:05:36
【问题描述】:

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

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

如果他发现一个现成的对象已经存在于缓存中,那么从下一次任何线程来,他们都会从缓存中取出它,以便在性能方面保持良好。

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

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

【问题讨论】:

  • 缓存是分发对它的副本的引用,还是手工复制?线程如何将更改写入缓存对象?这些写入是否绕过缓存?如果是这样,是否因为缓存上的副本过时而从缓存中弹出数据?
  • 这取决于您的缓存,请发布您的代码。
  • 不依赖于实例的线程安全吗?您还可以同步对缓存的访问并只允许一个线程占用您的实例。
  • 缓存如上维护。

标签: java multithreading caching


【解决方案1】:

有很多可能的解决方案:

  • 使用现有的缓存解决方案,例如EHcache
  • 使用 Spring 框架,它可以通过简单的@Cacheable annotation 轻松缓存方法的结果
  • 使用同步地图之一,例如ConcurrentHashMap
  • 如果您事先知道所有密钥,则可以使用lazy init code。请注意,此代码中的所有内容都是有原因的;更改get() 中的任何内容,它最终崩溃(最终==“您的单元测试将起作用,并且在生产运行一年后它会崩溃而没有任何问题”)。

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

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

[EDIT] 是的,即使地图已同步,这也可能发生。示例:

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

如果两个线程同时运行这段代码,computeNewValue() 将被调用两次。方法调用get()put() 是安全的 - 多个线程可以尝试同时放置,不会发生任何坏事,但这并不能保护您免受连续调用多个方法时出现的问题 并且地图的状态不能在它们之间改变。

【讨论】:

  • ConcurrentHashMap 不是同步映射。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

    简短的回答是肯定的。

    如果对象的创建成本很高,但需要以只读方式。我建议您将其设置为不可变的,这样您就可以获得访问速度快且线程安全的好处。

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

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

    【讨论】:

      【解决方案4】:

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

      Thread-safe cache of one object in java

      否则我不能推荐google guava library,特别是看看MapMaker类。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-11
        • 2017-10-15
        • 2011-03-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多