读写锁的实现
读取:没有线程正在做写操作且没有线程请求写操作
写入:没有线程正在做写操作
这里假设写操作的优先级比读操作高
写锁重入
当一个线程已经拥有写锁,才允许写锁重入
public class ReadWriteLock {
private Map<Thread, Integer> readingThreads = new HashMap<Thread, Integer>();//已经持有读锁的线程和对应线程获取读锁的次数
private int writeAccesses = 0;
private int writeRequest = 0;//请求写操作
private Thread writingThread = null;
public synchronized void lockWrite() throws InterruptedException{
writeRequest++;//写请求加1
Thread callingThread = Thread.currentThread();
//不能获得写权限,进入等待
if (!canGrantWriteAccess(writingThread)){
wait();
}
writeRequest--;
writeAccesses++;
writingThread = callingThread;
}
public synchronized void unlockWrite(){
writeAccesses--;
if (writeAccesses == 0){
writingThread = null;
}
notifyAll();
}
private boolean canGrantWriteAccess(Thread callingThread){
if (hasReaders()) return false;
if (writingThread == null) return true;//无线程持有写锁,返回true
if (!isWriter(callingThread)) return false;
return true;
}
//是否有线程持有读锁
private boolean hasReaders(){
return readingThreads.size() > 0;
}
//该线程是否拥有写锁
private boolean isWriter(Thread callingThread){
return callingThread == writingThread;
}
}
读锁升级到写锁
有时候,我们希望一个拥有读锁的线程,也可以获得写锁。这时候需要这个线程是唯一一个拥有读锁的线程。
public class ReadWriteLock2 {
private Map<Thread, Integer> readingThreads = new HashMap<Thread, Integer>();
private int writeAccesses = 0;
private int writeRequest = 0;
private Thread writingThread = null;
public synchronized void lockWrite()throws InterruptedException{
writeRequest++;
Thread callingThread = Thread.currentThread();
if (!canGrantWriteAccess(callingThread)){
wait();
}
writeRequest--;
writeAccesses++;
writingThread = callingThread;
}
public synchronized void unlockWrite(){
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 callingThread == writingThread;
}
//是唯一的读锁线程
private boolean isOnlyReader(Thread thread){
return readingThreads.size() == 1 &&
readingThreads.get(thread) != null;
}
}
可重入的ReadWriteLock的完整实现
public class ReadWriteLock3 {
private Map<Thread, Integer> readingThreads = new HashMap<>();
private int writeAccesses = 0;
private int writeRequest = 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);
}
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{
writeRequest++;
Thread callingThread = Thread.currentThread();
if (!canGrantWriteAccess(callingThread)){
wait();
}
writeRequest--;
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 ReadWriter");
}
writeAccesses--;
if (writeAccesses == 0){
writingThread = null;
}
notifyAll();
}
private boolean canGrantReadAccess(Thread callingThread){
if (isWriter(callingThread)) return true;
if (hasWriter()) return false;
if (isReader(callingThread)) return true;
if (hasWriteRequest()) return false;
return true;
}
private boolean canGrantWriteAccess(Thread callingThread){
if (isOnlyReader(writingThread)) 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 != null;
}
private boolean hasWriteRequest(){
return this.writeRequest > 0;
}
}