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

ReadWriteLock之公平锁解析(三)

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

    接下来跟着上一篇, 解析情景五和情景六

    情景五

    写读读

    public static void main(String[] args){
        final Printer printer = new Printer();
    
        Thread thread1 = new Thread(){
            @Override
            public void run() {
                try {
                    printer.write("test1");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        Thread thread2 = new Thread(){
            @Override
            public void run() {
                try {
                    printer.read("test2");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        Thread thread3 = new Thread(){
            @Override
            public void run() {
                try {
                    printer.read("test3");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        thread1.start();
        thread2.start();
        thread3.start();
    }
    
    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-0
        Thread current = Thread.currentThread();
        // c = 0
        int c = getState();
        // w = 0
        int w = exclusiveCount(c);
        // 不走此分支
        if (c != 0) {
            ......
        }
        if (writerShouldBlock() ||
            !compareAndSetState(c, c + acquires))
            return false;
        setExclusiveOwnerThread(current);
        return true;
    }
    
    static final class FairSync extends Sync {
        final boolean writerShouldBlock() {
            return hasQueuedPredecessors();
        }
    }
    
    public final boolean hasQueuedPredecessors() {
        Node t = tail; 
        Node h = head;
        Node s;
        // h和t都为null, 返回false
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }
    

    回到tryAcquire方法

    protected final boolean tryAcquire(int acquires) {
        Thread current = Thread.currentThread();
        int c = getState();
        int w = exclusiveCount(c);
        if (c != 0) {
            if (w == 0 || current != getExclusiveOwnerThread())
                return false;
            if (w + exclusiveCount(acquires) > MAX_COUNT)
                throw new Error("Maximum lock count exceeded");
            setState(c + acquires);
            return true;
        }
        // writerShouldBlock方法返回false
        if (writerShouldBlock() ||
            // 在此CAS假设是成功的
            // 所以不会走此分支
            !compareAndSetState(c, c + acquires))
            return false;
        // 设置获得写锁的线程为thread-0
        setExclusiveOwnerThread(current);
        // 返回true
        return true;
    }
    

    此时线程1获得写锁, 线程2开始执行

    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-1
        Thread current = Thread.currentThread();
        // c = 1
        int c = getState();
        // 此时线程1获得写锁
        // 并且当前线程是线程2
        // 所以会进入此分支
        if (exclusiveCount(c) != 0 &&
            getExclusiveOwnerThread() != current)
            return -1;
        ......
    }
    

    接下来回到acquireShared方法

    public final void acquireShared(int arg) {
        // tryAcquireShared返回-1, 进入此分支
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }
    
    private void doAcquireShared(int arg) {
        // 向队列中加入代表当前线程的节点
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                // 线程2是第一个被阻塞的
                // 所以其前序节点就是head
                // p此时就是head
                final Node p = node.predecessor();
                if (p == head) {
                    // 在进行阻塞或其他操作前再确认下是否可以获得锁
                    // 此时r = -1, 也就是确实无法获取到锁
                    int r = tryAcquireShared(arg);
                    // 不走此分支
                    if (r >= 0) {
                        ......
                    }
                }
                // 第一次循环不会阻塞, 第二次循环会被阻塞
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    

    此时线程2就被阻塞

    此时, 线程3开始执行

    // 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 = 1
        int c = getState();
        // 获得锁线程为thread-0, 进入此分支
        if (exclusiveCount(c) != 0 &&
            getExclusiveOwnerThread() != current)
            return -1;
        ......
    }
    

    回到acquireShared方法

    public final void acquireShared(int arg) {
        // tryAcquireShared返回-1, 进入此分支
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }
    
    private void doAcquireShared(int arg) {
        // 此时将thread-2加入队列尾部
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                // p代表被阻塞的线程thread-1, 不是head
                // 不走此分支
                if (p == head) {
                    ......
                }
                // 在第二次循环的时候会阻塞自身
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    

    情景六

    写读写

    线程1和线程2和情景五一样, 主要解析线程3

    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-2
        Thread current = Thread.currentThread();
        // c = 1
        int c = getState();
        // w = 1
        int w = exclusiveCount(c);
        if (c != 0) {
            // 虽然w = 1
            // 但是加锁线程为thread-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();
    }
    

    此时线程3被阻塞

    相关文章

      网友评论

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

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