1

When reading JDK codes, I tried to find some usage of ReentrantReadWriteLock, and found that the only usage is in javax.swing.plaf.nimbus.ImageCache.

I have two questions with the usage of ReentrantReadWriteLock here:

I can understand the readLock used in the getImage method, and the writeLock used in the setImage method, but why is a readLock used in the flush method? Isn't the flush method also some kind of "write", since it changes the map:

public void flush() {
    lock.readLock().lock();
    try {
        map.clear();
    } finally {
        lock.readLock().unlock();
    }
}

The other question: why not use a ConcurrentHashMap here, since it will provide some concurrent writes to different mapEntries and provide more concurrency than ReadWriteLock?

Jonny Henly
  • 4,023
  • 4
  • 26
  • 43
ZhaoGang
  • 4,491
  • 1
  • 27
  • 39

1 Answers1

1

Second Question First:

ReentrantReadWriteLocks can be used to improve concurrency in some uses of some kinds of Collections. This is typically worthwhile only when the collections are expected to be large, accessed by more reader threads than writer threads, and entail operations with overhead that outweighs synchronization overhead. - from ReentrantReadWriteLock Documentation

All of the points mentioned above correspond to an image cache. As for "why not use a ConcurrentHashMap?" - ImageCache uses a LinkedHashMap which has no concurrent implementation. For speculation as to why, refer to this SO question: Why there is no ConcurrentLinkedHashMap class in jdk?

First Question:

I too question why the flush method doesn't use the writeLock like the setImage method. After all it is structurally modifying the map.

After reviewing the javax.swing.plaf.nimbus.ImageCache and PixelCountSoftReference sources along with the ReentrantReadWriteLock and LinkedHashMap documentations, I'm left without a definitive answer. Although I'm further confused by flush using a readLock, since ReentrantReadWriteLock's documentation has the following example, where a writeLock is used when clearing a TreeMap.

// For example, here is a class using a TreeMap that is expected to be 
// large and concurrently accessed.
class RWDictionary {
    private final Map<String, Data> m = new TreeMap<String, Data>();
    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    private final Lock w = rwl.writeLock();

    // other code left out for brevity

    public void clear() {
        w.lock();  // write lock
        try { m.clear(); } // clear the TreeMap
        finally { w.unlock(); }
    }
}

The only thing I can do is speculate.

Speculation:

  • Maybe the author(s) made a mistake, highly unlikely but not impossible.
  • It's intentional. I have some ideas as to why it may be intentional, but I'm not sure how to word them and they're probably wrong.
  • The author(s) were the only ones using the ImageCache code and knew when and how (not) to use the flush method. This is unlikely as well.

It would be interesting to ask the author(s) why they used a readLock instead of a writeLock, via email, but no authors or emails are listed in the source. Perhaps sending an email to Oracle would result in an answer, I'm not to sure how to go about that.

Hopefully someone will come along and provide an actual answer. Good question.

Community
  • 1
  • 1
Jonny Henly
  • 4,023
  • 4
  • 26
  • 43