ReentrantReadWriteLock读写锁

ReentrantReadWriteLock是一把可重入读写锁,提高了读的性能。读写锁时如何实现了呢。

其实读写锁还是通过一个compareAndSet实现的,只是里面的state的含义不一样了,原先是表示线程的重入次数,现在对该变量做了拆分。高16位表示读线程的重入次数,第16位表示写线程的重入次数。

下面我们看几个变量和方法

static final int SHARED_SHIFT   = 16;
        //1 0000 0000 0000 0000 用于读线程重入一次
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
        //读线程最大重入次数
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
        //FFFF FFFF FFFF FFFF 用于计算写线程重入次数
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        //获取读线程重入次数        
        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
        //获取写线程重入次数
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

获取写锁

final boolean tryWriteLock() {
            Thread current = Thread.currentThread();
            int c = getState();
            //如果c等于0,说明空闲,如果非0,说明已经被占用了
            if (c != 0) {
                //获取写线程重入次数
                int w = exclusiveCount(c);
                
                //如果当前没有写线程,或者写线程不是当前线程,直接返回失败
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                    
                //如果写线程已经超过最大重入次数了,则报错
                if (w == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
            }
            
            //占用锁
            if (!compareAndSetState(c, c + 1))
                return false;
            setExclusiveOwnerThread(current);
            return true;
        }

获取读锁

final boolean tryReadLock() {
            Thread current = Thread.currentThread();
            for (;;) {
                int c = getState();
                //如果当前存在写锁,并且不是当前线程,则直接获取锁失败
                if (exclusiveCount(c) != 0 &&
                    getExclusiveOwnerThread() != current)
                    return false;
                //获取读锁重入次数
                int r = sharedCount(c);
                if (r == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                //读锁占用
                if (compareAndSetState(c, c + SHARED_UNIT)) {
                    if (r == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {
                        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;
                }
            }
        }
经验分享 程序员 微信小程序 职场和发展