【问题标题】:Query regarding read-write locks关于读写锁的查询
【发布时间】:2013-08-13 11:17:03
【问题描述】:
我正在研究 Java 并发 API,并试图了解读写锁的用处。 javadoc 说读写块维护一对锁,一个用于读取,另一个用于写入操作。虽然写锁是一个线程的独占访问,但多个线程可以获取读锁。因此,如果在读取部分我们所做的只是读取操作,并且无论如何我们都提供多线程访问,那么首先需要读取锁吗?是否存在读写锁真正有用的场景?
【问题讨论】:
标签:
java
multithreading
java.util.concurrent
【解决方案1】:
....首先有什么需要读锁
在阅读时,您需要防止写入者获取锁……直到所有读取者都完成。但是另一个阅读器获取锁是可以的。
在写入时,您需要防止读取器获取锁...直到写入器完成。
(换句话说,可以有一个写入器,或者多个读取器持有锁......但不能同时拥有。)
为了描述这一点,将行为描述为两个锁会很有帮助。 实际上在幕后发生的事情......是特定于实现的。
是否存在读写锁真正有用的场景?
嗯,是的。在您可以区分需要共享只读访问和需要独占读写(或只写)的线程的任何情况下,ReadWrite 锁允许比简单的Lock 或原始互斥锁更多的并发性。
【解决方案2】:
如果您在多个线程中读取数据,由于可见性问题,您可能看不到数据的最新更改。有很多层可以在每个线程的基础上缓存数据:CPU 缓存的不同层、RAM 访问缓冲区等。将读取锁定到位,您可以肯定,您始终在观察最新状态。
写锁更加强大,提供原子性访问以及最新更改的可见性。
这里使用不同类型的锁的主要原因是能够获得足够的同步级别,而不会为其他线程引入过多的开销和锁。
是否存在读写锁真正有用的场景?
当您有一些内存数据(数组、集合或其他)时非常有用,这些数据被不同的线程查询很多,但这些数据的更新很少发生。在这种情况下,拥有单独的锁(用于查询的读锁和用于更新的写锁)可能会给您带来显着的性能优势。
【解决方案3】:
拥有只读锁的原因是,如果其他线程有一个对象被锁定以进行写入,那么该对象的状态可能会不一致,因此您根本不想在没有锁的情况下开始读取它。获得读锁可确保 (1) 对象在您查看它时处于一致状态,因为没有其他线程正在修改它,并且 (2) 没有其他线程可以开始修改它,直到您'通过看它。我们将读锁作为一种单独的类型,因为如果通常有很多线程要读取但更新很少,那么读取器可以同时查看。