在许多教程中,我遇到了ReadWriteLock的非重入实现。
public class ReadWriteLock{
private int readers = 0;
private int writers = 0;
private int writeRequests = 0;
public synchronized void lockRead() throws InterruptedException{
while(writers > 0 || writeRequests > 0){
wait();
}
readers++;
}
public synchronized void unlockRead(){
readers--;
notifyAll();
}
public synchronized void lockWrite() throws InterruptedException{
writeRequests++;
while(readers > 0 || writers > 0){
wait();
}
writeRequests--;
writers++;
}
public synchronized void unlockWrite() throws InterruptedException{
writers--;
notifyAll();
}
}
题:
此类的对象(例如
lock
)在所有读取器和写入器线程之间共享以进行同步。假设Reader T1调用
lock.lockRead()
,这将获取锁定对象上的锁,而Reader T2同时在同一对象上调用lockRead()
。但是T1已经锁定了对象,因此T2应该被阻塞并在队列中等待。那么,代码如何允许多个读取器同时设置readLock?
请纠正我,知道我什么时候错了。
最佳答案
的确,没有2个线程可以同时执行lockRead()
方法的主体。但这对于读取器/写入器模式正常工作并具有预期的性能不是必需的。
重要的是,如果没有活动的编写器(未调用lockRead()
),wait
方法将快速返回。该方法结束时将释放该锁,从而允许另一个线程也获取读锁。
因此,是的,获取读锁(递增readers
)的操作已序列化。但是它发生得如此之快,以至于效果很好。
为了显示:
private ReadWriteLock lock = new ReadWriteLock(); // this instance is shared by all threads
public void ReadSomething() {
try {
lock.lockRead(); // serialized, but very quick
PerformWork(); // potentially slower, but is concurrent
} finally {
lock.unlockRead(); // serialized, but very quick
}
}
如果有2个线程尝试同时完全运行上述
ReadSomething()
方法,则确实只有一次线程能够一次执行lock.lockRead()
。但是,只要该方法为其中一个线程返回,第二个线程也将能够执行该方法。而且对lock.lockRead()
的调用是如此之快,以至于您甚至无法注意到一个线程正在等待另一个线程。重要的是两个线程都能够同时执行更多耗时的
PerformWork()
。