原文: http://tutorials.jenkov.com/java-concurrency/read-write-locks.html
參考譯文:https://blog.csdn.net/u011638883/article/details/18605761
讀寫鎖,解決多讀少寫的同步問題。
實現
讀獲取,無線程寫,也沒有線程請求寫操作。
寫獲取,沒有線程讀或者寫。
一個線程想要進行讀操作,必須滿足此時沒有寫操作,已經沒有寫請求。在這裏我們假定寫請求比讀請求更爲重要,因爲如果讀操作非常多,寫操作就很難獲取到鎖,很容易就進入到一個飢餓狀態。線程寫請求需要阻塞直到讀鎖全部釋放。
示例
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();
}
}
Read / Write Lock Reentrance
Read Reentrance
public class ReadWriteLock{
private Map<Thread, Integer> readingThreads = new HashMap<Thread, Integer>();
private int writers = 0;
private int writeRequests = 0;
public synchronized void lockRead() throws InterruptedException{
Thread callingThread = Thread.currentThread();
while(! canGrantReadAccess(callingThread)){
wait();
}
readingThreads.put(callingThread,
(getAccessCount(callingThread) + 1));
}
public synchronized void unlockRead(){
Thread callingThread = Thread.currentThread();
int accessCount = getAccessCount(callingThread);
if(accessCount == 1){ readingThreads.remove(callingThread); }
else { readingThreads.put(callingThread, (accessCount -1)); }
notifyAll();
}
private boolean canGrantReadAccess(Thread callingThread){
if(writers > 0) return false;
if(isReader(callingThread) return true;
if(writeRequests > 0) return false;
return true;
}
private int getReadAccessCount(Thread callingThread){
Integer accessCount = readingThreads.get(callingThread);
if(accessCount == null) return 0;
return accessCount.intValue();
}
private boolean isReader(Thread callingThread){
return readingThreads.get(callingThread) != null;
}
}
Write Reentrance
public class ReadWriteLock {
private Map<Thread, Integer> readingThreads = new HashMap<Thread, Integer>();
private int writeAccesses = 0;
private int writeRequests = 0;
private Thread writingThread = null;
public synchronized void lockWrite() throws InterruptedException {
writeRequests++;
Thread callingThread = Thread.currentThread();
while (!canGrantWriteAccess(callingThread)) {
wait();
}
writeRequests--;
writeAccesses++;
writingThread = callingThread;
}
public synchronized void unlockWrite() throws InterruptedException {
writeAccesses--;
if (writeAccesses == 0) {
writingThread = null;
}
notifyAll();
}
private boolean canGrantWriteAccess(Thread callingThread) {
if (hasReaders()) return false;
if (writingThread == null) return true;
if (!isWriter(callingThread)) return false;
return true;
}
private boolean hasReaders() {
return readingThreads.size() > 0;
}
private boolean isWriter(Thread callingThread) {
return writingThread == callingThread;
}
}
Read to Write Reentrance
public class ReadWriteLock {
private Map<Thread, Integer> readingThreads = new HashMap<Thread, Integer>();
private int writeAccesses = 0;
private int writeRequests = 0;
private Thread writingThread = null;
public synchronized void lockWrite() throws InterruptedException {
writeRequests++;
Thread callingThread = Thread.currentThread();
while (!canGrantWriteAccess(callingThread)) {
wait();
}
writeRequests--;
writeAccesses++;
writingThread = callingThread;
}
public synchronized void unlockWrite() throws InterruptedException {
writeAccesses--;
if (writeAccesses == 0) {
writingThread = null;
}
notifyAll();
}
private boolean canGrantWriteAccess(Thread callingThread) {
if (isOnlyReader(callingThread)) return true;
if (hasReaders()) return false;
if (writingThread == null) return true;
if (!isWriter(callingThread)) return false;
return true;
}
private boolean hasReaders() {
return readingThreads.size() > 0;
}
private boolean isWriter(Thread callingThread) {
return writingThread == callingThread;
}
private boolean isOnlyReader(Thread thread) {
return readers == 1 && readingThreads.get(callingThread) != null;
}
}
Write to Read Reentrance
public class ReadWriteLock{
private boolean canGrantReadAccess(Thread callingThread){
if(isWriter(callingThread)) return true;
if(writingThread != null) return false;
if(isReader(callingThread) return true;
if(writeRequests > 0) return false;
return true;
}
}
Fully Reentrant ReadWriteLock
public class ReadWriteLock {
private Map<Thread, Integer> readingThreads = new HashMap<Thread, Integer>();
private int writeAccesses = 0;
private int writeRequests = 0;
private Thread writingThread = null;
public synchronized void lockRead() throws InterruptedException {
Thread callingThread = Thread.currentThread();
while (!canGrantReadAccess(callingThread)) {
wait();
}
readingThreads.put(callingThread,
(getReadAccessCount(callingThread) + 1));
}
private boolean canGrantReadAccess(Thread callingThread) {
if (isWriter(callingThread)) return true;
if (hasWriter()) return false;
if (isReader(callingThread)) return true;
if (hasWriteRequests()) return false;
return true;
}
public synchronized void unlockRead() {
Thread callingThread = Thread.currentThread();
if (!isReader(callingThread)) {
throw new IllegalMonitorStateException("Calling Thread does not" +
" hold a read lock on this ReadWriteLock");
}
int accessCount = getReadAccessCount(callingThread);
if (accessCount == 1) {
readingThreads.remove(callingThread);
} else {
readingThreads.put(callingThread, (accessCount - 1));
}
notifyAll();
}
public synchronized void lockWrite() throws InterruptedException {
writeRequests++;
Thread callingThread = Thread.currentThread();
while (!canGrantWriteAccess(callingThread)) {
wait();
}
writeRequests--;
writeAccesses++;
writingThread = callingThread;
}
public synchronized void unlockWrite() throws InterruptedException {
if (!isWriter(Thread.currentThread()) {
throw new IllegalMonitorStateException("Calling Thread does not" +
" hold the write lock on this ReadWriteLock");
}
writeAccesses--;
if (writeAccesses == 0) {
writingThread = null;
}
notifyAll();
}
private boolean canGrantWriteAccess(Thread callingThread) {
if (isOnlyReader(callingThread)) return true;
if (hasReaders()) return false;
if (writingThread == null) return true;
if (!isWriter(callingThread)) return false;
return true;
}
private int getReadAccessCount(Thread callingThread) {
Integer accessCount = readingThreads.get(callingThread);
if (accessCount == null) return 0;
return accessCount.intValue();
}
private boolean hasReaders() {
return readingThreads.size() > 0;
}
private boolean isReader(Thread callingThread) {
return readingThreads.get(callingThread) != null;
}
private boolean isOnlyReader(Thread callingThread) {
return readingThreads.size() == 1 &&
readingThreads.get(callingThread) != null;
}
private boolean hasWriter() {
return writingThread != null;
}
private boolean isWriter(Thread callingThread) {
return writingThread == callingThread;
}
private boolean hasWriteRequests() {
return this.writeRequests > 0;
}
}