读操做触发条件:函数
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(); } } |
ReadWriteLockl类中经过读锁、写锁以两个锁的状态控制线程的读、写操做: writers表示当前正在使用写锁的线程数量; writeRequests表示等待请求写锁的线程数量; readers表示请求读锁的线程数量; 说明: 1.线程在获取读锁的时候,只要没有线程拥有写锁即writers==0同时没有线程请求写锁即writerRquests==0,那么线程就能成功获取读锁; 2.当一个线程想获取写锁的时候,会把写锁的请求数加1即writeRequests++,而后再尝试获取可否获取写锁,若是当前没有线程占用写锁即writers==0,那么此时就能成功获取写锁,同时writers++;若是wirters>0表示写锁此时被其余线程占用那么当前线程会被阻塞等待写锁释放时被唤醒。 3.写操做的优先级高于读操做的优先级体如今,线程请求读锁时会判断持有写锁的线程数和请求写锁的线程数,即while(writers > 0 || writeRequests > 0){wait();},而线程请求写锁时只须要判断持有写锁和读锁的线程数便可,即while(readers > 0 || writers > 0) {wait();} |
锁重入,是指同一线程 外层函数得到锁以后 ,内层递归函数仍然有获取该锁的代码,但不受影响。ReentrantLock 和synchronized 都是可重入锁,可重入锁最大的做用是避免死锁。
以自旋锁为例,若是自旋锁不是可重入锁的话,若是一个线程在第一次获取锁执行同步代码前提下,第二次再执行同步代码就产生了死锁。
之前面的代码为例:this
writers > 0 || writeRequests > 0
,由于Thread请求写锁的缘由致使该条件成立,Thread1进入阻塞状态,死锁出现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; } } |
读锁的可重入有两种状况: 1.当前程序中没有线程请求写锁(这种状况是几乎不存在) 2.当前程序中有线程请求写锁也有线程请求读锁,而且有线程已经获得了读锁 第二种状况是最多见的,所以咱们须要知道哪些线程是持有读锁的 所以在代码中使用Map来存储已经持有读锁的线程和对应线程获取读锁的次数,经过Map就能够判断对应的线程是否持有读锁,调整以后的代码在原有判断"writeRequests >0"和"writers > 0"还加上了判断当前线程是否持有读锁的判断逻辑 |
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; } } |
写锁重入,是在当前程序里有且只有一个线程持有写锁,若是写锁重入,说明当前程序中没有线程持有读锁,写锁重入只有持有写锁的线程才能重入,其余的线程就须要进入阻塞状态 |
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; } }