读写锁ReentrantReadWriteLock

读线程与读线程之间不互斥

public interface ReadWriteLock {
    Lock readLock();

    Lock writeLock();
}

ReentrantReadWriteLock实现了这个接口
ReentrantReadWriteLock的使用方法

ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); 
Lock readLock = readWriteLock.readLock(); 
readLock.lock(); 
readLock.unlock(); 
Lock writeLock = readWriteLock.writeLock(); 
writeLock.lock(); 
writeLock.unlock();

ReentrantReadWriteLock的实现
构造方法

    public ReentrantReadWriteLock() {
    	//是否公平
        this(false);
    }
    public ReentrantReadWriteLock(boolean fair) {
    	//使用公平或者非公平的sync
        sync = fair ? new FairSync() : new NonfairSync();
        //readerLock 和writerLock 使用同一个sync
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }

读写锁和互斥锁一样也是用state来表示锁的状态的,只是操作方式不同

abstract static class Sync extends AbstractQueuedSynchronizer {
	//...
        static final int SHARED_SHIFT   = 16;
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        //int的长度是32位,这里会把state作为参数传入,然后取state的高16位
        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
        //取state的低16位
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
	//...
}

ReentrantReadWriteLock会把state变量拆成两半,低16位,用来记录写锁。如果低16位的值等于5,表示一个写线程重入了5次。高16位,用来记录读锁。例如,高16位的值等于5,既可以表示5个读线程都拿到了该锁;也可以表示一个读线程重入了5次

当state=0时,说明既没有线程持有读锁,也没有线程持有写锁;当state != 0时,要么有线程持有读锁,要么有线程持有写锁,两者不能同时成立,因为读和写互斥。这时再进一步通过sharedCount(state)和exclusiveCount(state)判断到底是读线程还是写线程持有了该锁。

ReentrantReadWriteLock的两个内部类ReadLock和WriteLock中使用state变量

	public static class ReadLock implements Lock, java.io.Serializable {
        private final Sync sync;
        protected ReadLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }
        public void lock() {
            sync.acquireShared(1);
        }
        public void unlock() {
            sync.releaseShared(1);
        }
    }

    public static class WriteLock implements Lock, java.io.Serializable {
        private final Sync sync;
        protected WriteLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }
        public void lock() {
            sync.acquire(1);
        }
        public void unlock() {
            sync.release(1);
        }
    }

acquire/release、acquireShared/releaseShared 是AQS里面的两对模板方法。

    public final void acquireShared(int arg) {
    	//由AQS的子类sync实现
        if (tryAcquireShared(arg) < 0)
        	//获得锁失败把自己加入等待获取锁队列,阻塞线程等待唤醒
            doAcquireShared(arg);
    }
    public final boolean releaseShared(int arg) {
    	//由AQS的子类sync实现
        if (tryReleaseShared(arg)) {
        	//唤醒挂起的线程
            doReleaseShared();
            return true;
        }
        return false;
    }

    public final void acquire(int arg) {
    	//由AQS的子类sync实现
        if (!tryAcquire(arg) &&
        	//获得写锁失败把自己加入阻塞队列
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            //响应中断
            selfInterrupt();
    }

    public final boolean release(int arg) {
    	//由AQS的子类sync实现
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
            	//唤醒线程
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

ReentrantReadWriteLock中的sync

	//非公平的sync
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -8159625535654395037L;
        //写线程是否应该阻塞
        final boolean writerShouldBlock() {
        	//非公平锁不阻塞
            return false; 
        }
        //读线程是否应该阻塞
        final boolean readerShouldBlock() {
        	//队列中第一个是写线程则阻塞
            return apparentlyFirstQueuedIsExclusive();
        }
    }
	//公平的sync
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -2274990926593161451L;
        //写线程是否应该阻塞
        final boolean writerShouldBlock() {
        	//如果队列中已经有线程在排队则阻塞
            return hasQueuedPredecessors();
        }
        //读线程是否应该阻塞
        final boolean readerShouldBlock() {
            return hasQueuedPredecessors();
        }
    }

写锁的实现

        public boolean tryLock( ) {
            return sync.tryWriteLock();
        }
        final boolean tryWriteLock() {
            Thread current = Thread.currentThread();
            //获得state
            int c = getState();
            //当state不等于0的时候说明有线程获取了锁
            if (c != 0) {
            	//获得写线程的数量
                int w = exclusiveCount(c);
                //如果写线程==0说明持有锁的是读线程,或者当前线程不是排它锁的持有线程
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                if (w == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
            }
            //cas将state+1重入
            if (!compareAndSetState(c, c + 1))
                return false;
            //设置排它锁的持有线程为当前线程
            setExclusiveOwnerThread(current);
            return true;
        }
        
		//lock的时候调用tryAcquire,这里是fair的sync
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
            	//前面没有其他线程
                if (!hasQueuedPredecessors() &&
                	//cas设置state为acquires
                    compareAndSetState(0, acquires)) {
                    //设置排它锁线程为当前线程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //如果排它锁的持有线程为当前线程
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }


    public void unlock() {
        sync.release(1);
    }

    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            //唤醒队列里面的第一个线程
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

读锁的实现

    public boolean tryLock() {
        return sync.tryReadLock();
    }
    final boolean tryReadLock() {
            Thread current = Thread.currentThread();
            for (;;) {
                int c = getState();
                //如果排它锁的持有线程是写线程,并且当前线程不是持有锁线程
                if (exclusiveCount(c) != 0 &&
                    getExclusiveOwnerThread() != current)
                    return false;
                //获得读锁的state
                int r = sharedCount(c);
                if (r == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                //cas设置读锁
                if (compareAndSetState(c, c + SHARED_UNIT)) {
               		//如果r=0说明当前线程是第一个读线程
                    if (r == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    //第一个读线程是当前线程
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {
                    // 如果firstReader不是当前线程,则从ThreadLocal中获取当前线程的读锁个数,并设置当前线程持有的读锁个数
                        HoldCounter rh = cachedHoldCounter;
                        if (rh == null || rh.tid != getThreadId(current))
                            cachedHoldCounter = rh = readHolds.get();
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        rh.count++;
                    }
                    return true;
                }
            }
        }
        
    public void lock() {
        sync.acquireShared(1);
    }
    public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
        	//获取锁失败,将当前线程加入阻塞队列
            doAcquireShared(arg);
    }
    
    public void unlock() {
        sync.releaseShared(1);
    }

    public final boolean releaseShared(int arg) {
    	//cas设置读线程的state
        if (tryReleaseShared(arg)) {
        	//唤醒线程
            doReleaseShared();
            return true;
        }
        return false;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值