0

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).

Vinay Sharma
  • 1,163
  • 1
  • 10
  • 20
  • ConcurrentHashMap would definitely work but you could implement your resource in a way where the caller doesn't have to hold the readlock (you could grab the readlock internally when the read is called) and similarly with the writelock – David Jul 02 '19 at 08:44
  • @David would you like to share little more details. – Vinay Sharma Jul 02 '19 at 10:25

1 Answers1

0

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!
}
David
  • 589
  • 6
  • 21