Guava Cache,如何在删除时阻止访问

时间:2014-09-22 08:48:36

标签: java caching synchronization guava

我有线程A,向Guava Cache插入一个新元素,并且由于Size策略,缓存将驱逐与键Y相关联的元素。

不幸的是,Y的删除过程R需要很长时间,并且在Y处理期间(已经被驱逐但仍然在R中),还有另一个线程B试图获得与密钥Y相关联的数据。

基本上,R将尝试更新密钥Y的数据库,并且当该值未更新时,线程B尝试访问数据库以获取与密钥Y相关联的值,这仍然是旧值。

问题是:当R正在执行其工作时,如何阻止线程B使用键Y访问元素?

1 个答案:

答案 0 :(得分:3)

你说的是Guava Cache,但是没有代码示例,所以我给出了一般答案。

对于下面我假设你有一个“加载缓存”又名“自填充缓存”模式。

解决方案1: 正确设计缓存交互和数据库事务。

一旦启动了事务,更新过程就会使缓存条目无效。

  begin transaction
  touch some of the entry data with SQL UPDATE to have it in the transaction
  remove the entry from the cache
  ....
  now you can do more operations on the database regarding the entry data
  if you have the proper isolation level, reads from the database will stall
  until the transaction is committed
  ....
  end transaction

如果从缓存中删除条目然后启动事务,则会引入竞争条件。

解决方案2: 使用阻止同一键/条目上的并发操作的缓存。

看看ehcache Blocking Cache。或者查看cache2k,其中阻止行为是默认行为。

但是,您需要自己在加载程序级别上执行额外的锁定。例如。比如下面的例子。

解决方案3: 在缓存顶部自行锁定并包装所有缓存操作。例如。有类似的东西:

 Cache cache;
 Lock[] locks = new Lock[16];
 { /* initialize locks */ }

 public Object get(Object key) {
   int idx = key.hashCode() % locks.length;
   locks[idx].lock();
   try { return cache.get(key); 
   } finally { locks[idx].unlock(); }
 }

 public void update(Object key, Object obj) {
   int idx = key.hashCode() % locks.length;
   locks[idx].lock();
   try { return cache.put(key, obj); 
   } finally { locks[idx].unlock(); }
 }

您还可以从ehcache查看BlockingCache实现,并从中获取灵感。

玩得开心!