Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
376 views
in Technique[技术] by (71.8m points)

java - Guava Cache, how to block access while doing removal

I have thread A, inserting a new element to Guava Cache, and because of the Size policy, the cache will evict element associated with key Y.

Unfortunately, the removal process R of Y takes long, and during the time Y is being process by R (already evicted but still in R), there is another thread B trying to get data associated with key Y.

Basically, R will try to update the database for the key Y, and while that value is not updated, thread B try to access the database for value associated with key Y, which is still the old value.

Question is: how can I block thread B from accessing element with key Y while R is doing its job?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You stated Guava Cache, but there is no code example, so I give a general answer.

For the below I assume that you have a "loading cache" aka "self populating cache" schema.

Solution 1: Properly design your cache interactions and database transactions.

The update process invalidates the cache entry, as soon a transaction is started on it.

  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

If you remove the entry from the cache and then start the transaction you introduce a race condition.

Solution 2: Use caches that block out concurrent operations on the same key/entry.

Take a look on ehcache Blocking Cache. Or take a look on cache2k where the blocking behaviour is the default.

But, however, you need to do additional locking on the loader level by yourself. E.g. like the example below.

Solution 3: Do the locking by yourself on top of the cache and wrap all cache operations. E.g. with something like:

 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(); }
 }

You can also look at the BlockingCache implementation from ehcache and take some inspiration from there.

Have fun!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...