0

In my code I'm using ReentrantReadWriteLock to guard some paired read/write operations:

public class AgreementCache {
    
    private final ConcurrentMap<String, Agreement> agreements = new ConcurrentHashMap<>();

    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();


    public Agreement putIntoCache(String key, Function<String, Agreement> valueSupplyingFunction) {
        Lock lock = readWriteLock.writeLock();
        try {
            lock.lock();
            return agreements.put(key, valueSupplyingFunction.apply(key));
        } finally {
            lock.unlock();
        }
    }

    public void drainCache(Map<String, Agreement> destination) {
        Lock lock = readWriteLock.readLock(); // <--- !!!
        try {
            lock.lock();
            destination.putAll(agreements);
            agreements.clear(); // <--- !!!
        } finally {
            lock.unlock();
        }
    }

    public Agreement getFromCache(String key) {
        Lock lock = readWriteLock.readLock();
        try {
            lock.lock();
            return agreements.get(key);
        } finally {
            lock.unlock();
        }
    }
}

Here in put() method I need to ensure that mapping function is executed atomically along with putting the computed value into the map. At the same time I need to enforce raceless drain() operation, i.e. I need to make sure that no data will be put into the map while draining its contents. Currently I use writeLock in put() method and readLock() in drain() method, but I suspect this is wrong, because after map.putAll() I clear the map which is a modifying operation.

So my question is whether I need to use writeLock in drain() method or I can still rely on readLock()?

Sergey Tsypanov
  • 3,265
  • 3
  • 8
  • 34
  • 2
    Short answer: `clear()` modifies the map, so of course, you need a write lock. Long answer: just think of it, the read lock allows concurrent executions of `drainCache(…)` with one thread being in the middle of `destination.putAll(agreements)` when the other is executing `agreements.clear()`. That’s, by the way, the only problematic race condition in your code. Since the other methods use the lock only to guard a single `put` or `get`, they would also work with a `ConcurrentHashMap` alone, without locking. – Holger Feb 08 '23 at 10:03

0 Answers0