Reentrantlock

2020-08-31  本文已影响0人  ppamos

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),尝试重新获取锁。

上一篇下一篇

猜你喜欢

热点阅读