Java并发之读/写锁

读写锁的实现

读取:没有线程正在做写操作且没有线程请求写操作
写入:没有线程正在做写操作

这里假设写操作的优先级比读操作高

写锁重入

当一个线程已经拥有写锁,才允许写锁重入

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;

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值