美文网首页
Reentrantlock

Reentrantlock

作者: ppamos | 来源:发表于2020-08-31 10:02 被阅读0次

    Reentrantlock是jdk提供的可重入锁的实现,它分为非公平锁和公平锁。公平锁是那个线程等待锁时间最长,那个就获得锁。非公平锁是那个抢到锁,锁就归哪一个。

    Reentrantlock.lock()非公平锁源码解析。

     final void lock() {
                if (compareAndSetState(0, 1))
                //尝试获取锁,如果获取成功,则设当前线程为已获取锁的线程。
                    setExclusiveOwnerThread(Thread.currentThread());
                else
                //重入锁的实现以及把争抢锁的线程放入队列中
                    acquire(1);
            }
    
           final boolean nonfairTryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                if (c == 0) {
                //再次判断一下上一个线程是否已经释放了锁。
                    if (compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
                else if (current == getExclusiveOwnerThread()) {
                //如果当前线程与获得锁的线程是同一个,则他为重入锁。
                //重入次数加 1
                    int nextc = c + acquires;
                    if (nextc < 0) // overflow
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
                }
                return false;
            }
    

    如果抢占不了锁权限,则把当前线程放入AQS同步队列中

        private Node addWaiter(Node mode) {
            Node node = new Node(Thread.currentThread(), mode);
            // Try the fast path of enq; backup to full enq on failure
            Node pred = tail;
            if (pred != null) {
                node.prev = pred;
                if (compareAndSetTail(pred, node)) {
                    pred.next = node;
                    return node;
                }
            }
            //新建一个AQS队列
            enq(node);
            return node;
        }
    
        private Node enq(final Node node) {
            for (;;) {
                Node t = tail;
                if (t == null) { // Must initialize
                //第一次进入新建一个头结点
                    if (compareAndSetHead(new Node()))
                    //头结点和尾结点设置为同一结点
                        tail = head;
                } else {
                    node.prev = t;
                    //把当前线程设为尾部结点,加入到AQS队列中
                    if (compareAndSetTail(t, node)) {
                        t.next = node;
                        return t;
                    }
                }
            }
        }
    
    加入aqs队列示意图.jpg
    final boolean acquireQueued(final Node node, int arg) {
            boolean failed = true;
            try {
                boolean interrupted = false;
                for (;;) {
                    final Node p = node.predecessor();
                    //如果当前结点的上个结点为头结点
                    //尝试争抢锁
                    //争抢锁成功,把当前结点设为头结点,去掉之前的头结点
                    //等待gc回收之前头结点
                    if (p == head && tryAcquire(arg)) {
                        setHead(node);
                        p.next = null; // help GC
                        failed = false;
                        return interrupted;
                    }
                    //设置标志位为-1,并且中断当前线程
                    if (shouldParkAfterFailedAcquire(p, node) &&
                        parkAndCheckInterrupt())
                        interrupted = true;
                }
            } finally {
                if (failed)
                    cancelAcquire(node);
            }
        }
    
     private final boolean parkAndCheckInterrupt() {
            LockSupport.park(this);//中断线程
            return Thread.interrupted();
        }
    
    线程获取不到锁终端示意图.jpg
     public final boolean release(int arg) {
     //把锁次数减1,如果锁次数为0,则释放当前锁
            if (tryRelease(arg)) {
                Node h = head;
                if (h != null && h.waitStatus != 0)
             //唤醒头结点的下一个结点,如果它存在的话
                    unparkSuccessor(h);
                return true;
            }
            return false;
        }
    

    线程唤醒后,会从中断的地方开始执行,调用acquireQueued()方法里面的tryAcquire(arg),尝试重新获取锁。

    相关文章

      网友评论

          本文标题:Reentrantlock

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