Read / Write Locks in Java

原文: 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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章