Java concurrency problem with Servlet requests

93 Views Asked by At

What is the right way to solve following problem?

Writing a logic where at a same time 100 reader(Servlet requests) or one writer(Servlet requests) can be accessing critical section for one key in a map(Cache). If writer comes into the picture in that case all reader should stop there progress and should restart once writer done with critical section processing(Re population cache element for same key).

I implemented one of the solution like in this question, where one instance of Resource class will be associated with single key.

class Resource {
  private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
  private final Lock rlock = lock.readLock();
  private final Lock wlock = lock.writeLock();

  void read() { ... /* caller has to hold the read lock */ ... }
  void write() { ... /* caller has to hold the write lock */ ... }

  Lock readLock() { return rlock; }
  Lock writeLock() { return wlock; }
}

Previously I implemented simple logic using Semaphore where I have associated one semaphore instance with single key and used 100 permits for the same and if writer thread is coming into the picture in that case I consumed all remaining permits(drainPermits) and letting all permit free by all readers and putted writer thread in waiting queue. But it leads to starvation to writer.

Other thing I was thinking that using ConcurrentHashMap could solve it? As ConcurrentHashMap have key based locking internally(Segments).

1

There are 1 best solutions below

0
David On

You don't have to expose the locking to the user of the resource, however if you start implementing that pattern you soon discover that you may as well use a ConcurrentHashMap which is actually optimized well for synchronized access

class Resource {
  private Cache<Key, Value> yourcache;
  private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
  private final Lock rlock = lock.readLock();
  private final Lock wlock = lock.writeLock();

  Value read(Key key) { try {
rlock.lock();
return yourcache.get(key)
} finally {
rlock.unlock();
}
}
  void write(Key key) { ... /* similar pattern to above */ ... }

  Lock readLock() { return rlock; } //don't expose these at all!
  Lock writeLock() { return wlock; }//don't expose these at all!
}