在读取JDK代码时,我试图找到ReentrantReadWriteLock
的一些用法,发现唯一的用法是在javax.swing.plaf.nimbus.ImageCache
。
我对这里ReentrantReadWriteLock
的使用有两个问题:
我可以理解getImage
方法中使用的readLock
,以及setImage
方法中使用的writeLock
,但是为什么在flush
方法中使用readLock
?flush
方法不也是某种"写入"吗,因为它会更改地图:
public void flush() {
lock.readLock().lock();
try {
map.clear();
} finally {
lock.readLock().unlock();
}
}
另一个问题:为什么不在这里使用ConcurrentHashMap
,因为它会向不同的mapEntries
提供一些并发写入并提供比ReadWriteLock
更多的并发性?
第二个问题:
ReentrantReadWriteLocks
可用于在某些类型的集合的某些用途中提高并发性。通常,仅当集合预计很大、由比编写器线程更多的读取器线程访问,并且需要开销超过同步开销的操作时,这才值得。- 来自ReentrantReadWriteLock文档
上面提到的所有点都对应于图像缓存。至于"为什么不使用ConcurrentHashMap
?">——ImageCache
使用没有并发实现的LinkedHashMap
。有关原因的推测,请参阅以下 SO 问题:为什么 jdk 中没有 ConcurrentLinkedHashMap 类?
第一个问题:
我也质疑为什么flush
方法不像setImage
方法那样使用writeLock
。毕竟,它是在结构上修改地图。
在查看了javax.swing.plaf.nimbus.ImageCache
和PixelCountSoftReference
来源以及ReentrantReadWriteLock
和LinkedHashMap
文档后,我没有明确的答案。虽然我对flush
使用readLock
感到更加困惑,因为ReentrantReadWriteLock's
文档有以下示例,其中在清除TreeMap
时使用writeLock
。
// 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(); }
}
}
我唯一能做的就是推测。
投机:
- 也许作者犯了一个错误,不太可能,但并非不可能。
- 这是故意的。我有一些关于为什么可能是故意的想法,但我不确定如何措辞,他们可能是错误的。
- 作者是唯一使用
ImageCache
代码的人,并且知道何时以及如何(不(使用flush
方法。这也不太可能。
通过电子邮件询问作者为什么他们使用readLock
而不是writeLock
会很有趣,但来源中没有列出作者或电子邮件。也许向Oracle发送电子邮件会产生答复,我不确定该怎么做。
希望有人会来提供实际的答案。问得好。