Home > Back-end >  Allow only first thread to update cache while other threads read
Allow only first thread to update cache while other threads read

Time:01-04

I have multiple threads reading an in memory cache. The behavior I want is to refresh the cache every 5min. The problem is I don't know how to solve is how to force only one thread to update the cache while multiple threads still can read the cache.

This is a rough example of the code I have:

public synchronized boolean readCache(int id) {
  if (cache.hasExpired()) {
    updateCache();
  }
  return cache.get(id);
}

This works. However, it limits the implementation that only a single thread can read the cache at any instance. Is there a better way to do this?

CodePudding user response:

This is a classic double-checking problem:

// Note: the method isn't synchronized
public boolean readCache(int id) {
  // First check - quick check outside the lock.
  // If the cache isn't expired, no need to acquire a lock
  if (cache.hasExpired()) {
    // This thread may have to update the cache, so acquire the lock:
    synchronized (someSharedLock) {
      // Under the lock, double-check a different thread didn't update the cache
      // while we were waiting for the lock
      if (cache.hasExpired()) {
        updateCache();
      }
    }
  }

  // The cache is now definitely not expired, use it
  return cache.get(id);
}

CodePudding user response:

I have multiple threads reading an in memory cache. The behavior I want is to refresh the cache every 5min. The problem is I don't know how to solve is how to force only one thread to update the cache while multiple threads still can read the cache.

There are a couple of ways you can do this.

  • You could use the ReentrantReadWriteLock and have each thread get a read-lock on the cache and but then attempt to get a write-lock if the cache needs to be updated – only one thread will get the write-lock. It is important to note that when the cache is being updated, no threads can be reading the cache. This may or may not be what you want.

  • Another mechanism could be to use the atomic classes compareAndSet(...) method so that if multiple threads determine that the cache needs to be updated, only one thread would win. The pseudo code would be:

    get cache value
    see if cache needs updating
    try to update the atomic field with our id
    if it worked then update the cache
    else some other thread is updating the cache, return stale value for now
    

In terms of race conditions between the cache being stale or not, you will either need something as heavy as a synchronized lock or you are going to have to put up with some stale data around the time the cache needs to be updated – this may depend on how long it takes to update the cache. Either a thread requests the value a nanosecond before it expires or it doesn't. If the value must be updated every 5 minutes then and you don't want to use synchronized then you should probably update the cache more frequently – like every 4 minutes and 50 seconds.

It is important to note that however you update the cache, the cache itself will need to have its memory synchronized. The cache will need to be ConcurrentHashMap or a volatile object so that the threads can read the update cache values and one of them van update the value when appropriate.

  •  Tags:  
  • Related