美文网首页
ReadWriteLock之公平锁解析(二)

ReadWriteLock之公平锁解析(二)

作者: 436048bfc6a1 | 来源:发表于2021-11-22 16:01 被阅读0次

    接下来跟着上一篇, 解析情景三和情景四

    情景三

    读写读

    线程1的获得读锁的操作和情景一相同, 接下来从线程2开始分析

    public void lock() {
        sync.acquire(1);
    }
    
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    
    protected final boolean tryAcquire(int acquires) {
        // thread-1
        Thread current = Thread.currentThread();\
        // c = 65536
        int c = getState();
        // w = 0
        int w = exclusiveCount(c);
        if (c != 0) {
            // 进入此分支
            if (w == 0 || current != getExclusiveOwnerThread())
                return false;
           ......
        }
        ......
    }
    

    之后返回acquire方法

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            // 最后thread-1将自己加入队列并阻塞
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    

    此时线程2开始执行

    // ReadLock
    public void lock() {
        sync.acquireShared(1);
    }
    
    public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }
    
    protected final int tryAcquireShared(int unused) {
        // thread-2
        Thread current = Thread.currentThread();
        // c = 65536
        int c = getState();
        // 由于线程1(写操作)被阻塞, 没有获取写锁
        // 不走此分支
        if (exclusiveCount(c) != 0 &&
            getExclusiveOwnerThread() != current)
            return -1;
        // r = 1
        int r = sharedCount(c);
        if (!readerShouldBlock() &&
            r < MAX_COUNT &&
            compareAndSetState(c, c + SHARED_UNIT)) {
                ......
            }
            return 1;
        }
        ......
    }
    
    static final class FairSync extends Sync {
        final boolean readerShouldBlock() {
            return hasQueuedPredecessors();
        }
    }
    
    public final boolean hasQueuedPredecessors() {
        Node t = tail;
        Node h = head;
        Node s;
        // 由于thread-1被阻塞, 所以head和tail不相等
        return h != t &&
            // 队列中的末尾是thread-1, 非当前线程thread-2
            // 返回true
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }
    

    说明在队列中还有排队的线程, 返回tryAcquireShared

    protected final int tryAcquireShared(int unused) {
        Thread current = Thread.currentThread();
        int c = getState();
        if (exclusiveCount(c) != 0 &&
            getExclusiveOwnerThread() != current)
            return -1;
        int r = sharedCount(c);
        // 此读线程应该被阻塞
        if (!readerShouldBlock() &&
            r < MAX_COUNT &&
            compareAndSetState(c, c + SHARED_UNIT)) {
            ......
        }
        // 走此分支
        return fullTryAcquireShared(current);
    }
    
    final int fullTryAcquireShared(Thread current) {
        HoldCounter rh = null;
        for (;;) {
            // c = 65536
            int c = getState();
            // 此时希望获取写锁的线程二被阻塞, 不走此分支
            if (exclusiveCount(c) != 0) {
                if (getExclusiveOwnerThread() != current)
                    return -1;
            }
            // 由于此时队列中有线程1, 所以可以进入此分支 
            else if (readerShouldBlock()) {
                // firstReader是线程1, 当前线程为线程3
                // 不走此分支
                if (firstReader == current) {
                    // assert firstReaderHoldCount > 0;
                } 
                else {
                    if (rh == null) {
                        // 由于只有线程1获得读锁
                        // 所以cachedHoldCounter为null
                        rh = cachedHoldCounter;
                        // 进入此分支
                        if (rh == null || rh.tid != getThreadId(current)) {
                            // 创建HoldCounter对象(对应当前线程)
                            rh = readHolds.get();
                            // 此时当前线程没有重新获得读锁
                            if (rh.count == 0)
                                // 删除当前线程对应的
                                readHolds.remove();
                        }
                    }
                    // 返回-1
                    if (rh.count == 0)
                        return -1;
                }
            }
            ......
        }
    }
    

    回到acquireShared方法

    public final void acquireShared(int arg) {
        // tryAcquireShared最终返回-1
        // 进入该分支
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }
    
    private void doAcquireShared(int arg) {
        // 将代表当前线程的node加入队列中
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                // p代表线程1
                final Node p = node.predecessor();
                // p与head是不相等的, 不走此分支
                if (p == head) {
                    ......
                }
                // 第一次循环不会阻塞
                // 第二次循环会到parkAndCheckInterrupt被阻塞
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    

    情景四

    读写写

    和情景三类似, 只不过是线程三是写操作

    // WriteLock
    public void lock() {
        sync.acquire(1);
    }
    
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    
    protected final boolean tryAcquire(int acquires) {
        // current为thread-2
        Thread current = Thread.currentThread();
        // c = 65536
        int c = getState();
        // w = 0
        int w = exclusiveCount(c);
        if (c != 0) {
            // 进入此分支
            if (w == 0 || current != getExclusiveOwnerThread())
                return false;
            ......
        }
        ......
    }
    

    回到acquire方法中

    public final void acquire(int arg) {
        // 由于tryAcquire返回false
        if (!tryAcquire(arg) &&
            // 进入此分支
            // 创建代表当前线程的节点
            // 并加入队列后被阻塞
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    

    相关文章

      网友评论

          本文标题:ReadWriteLock之公平锁解析(二)

          本文链接:https://www.haomeiwen.com/subject/oxrbtrtx.html