【问题标题】:Locking Cache Key without Locking the entire Cache锁定缓存键而不锁定整个缓存
【发布时间】:2010-04-14 18:59:08
【问题描述】:

我有 servlet 缓存用户信息,而不是在每次请求时从用户存储中检索它(共享 Ehcache)。我遇到的问题是,如果客户端是多线程的,并且他们在通过身份验证之前发出了多个同时请求,那么我会在我的日志中得到这个:

Retrieving User [Bob]
Retrieving User [Bob]
Retrieving User [Bob]
Returned [Bob] ...caching
Returned [Bob] ...caching
Returned [Bob] ...caching 

我想要的是第一个请求将调用用户服务,而其他两个请求被阻止 - 当第一个请求返回,然后缓存对象时,其他两个请求通过:

Retrieving User [Bob]
blocking...
blocking...
Returned [Bob] ...caching
[Bob] found in cache
[Bob] found in cache

我考虑过锁定字符串“Bob”(因为由于实习,它总是同一个对象,对吧?)。那行得通吗?如果是这样,我如何跟踪缓存中实际存在的键并围绕它们构建锁定机制,一旦检索到有效对象,它将返回。谢谢。

【问题讨论】:

    标签: java performance caching concurrency


    【解决方案1】:

    如果您对锁没有独占控制权,则无法保证不会出现死锁。实习生String 是全球可见的,所以他们是一个糟糕的候选人。

    相反,在键和它们对应的锁之间使用映射。您可以使用同步访问并发映射,或使用ConcurrentMap。我不确定哪个更便宜,但我倾向于ConcurrentMap,因为它简洁地表达了您的意图。

    ReadWriteLock trial = new ReentrantReadWriteLock(fair);
    ReadWriteLock lock = locks.putIfAbsent(key, trial);
    if (lock == null) {
      /* The current thread won the race to create lock for key. */
      lock = trial;
    }
    

    (使用ReadWriteLock 是可选的;使用它,您可以做一些花哨的事情,例如允许多个线程并发读取缓存值,但在需要更新值时仍然让另一个线程获得排他锁。)

    创建大量由于锁已经存在而最终被丢弃的锁可能会很昂贵。或者,您可以使用没有java.util.concurrent 的旧运行时。在这种情况下,您可以在地图上同步:

    Object lock;
    synchronized (locks) {
      if (locks.containsKey(key))
        lock = locks.get(key);
      else {
        lock = new Object();
        locks.put(key, object);
      }
    }
    

    【讨论】:

    • 这与我的想法非常接近,由于某种原因,锁定实习字符串似乎是一个非常糟糕的主意。但是在这种情况下,我会锁定 Map 上的每个调用 - 但我想这与我的缓存没有什么不同(性能方面),它由所有线程共享。我认为即使这种开销仍然比对我的用户身份验证提供程序进行多次不需要的调用要快得多。
    【解决方案2】:

    我考虑过锁定字符串“Bob”(因为由于实习,它总是同一个对象,对吧?)。这样行吗?

    I've previously tried this and it actually doesn't work quite like you might expect。您需要确保首先在字符串上调用intern();但是,在实习生字符串上进行同步实际上是一个非常糟糕的主意。

    【讨论】:

      【解决方案3】:

      如果您使用 Map 进行缓存,则锁定键将按照您的建议进行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-03-21
        • 2012-05-29
        • 2017-02-20
        • 2019-03-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多