关于java:JDK8-new-ReentrantLock加锁流程一

32次阅读

共计 3158 个字符,预计需要花费 8 分钟才能阅读完成。

new ReentrantLock(); 加锁流程:

// 默认执行 NonfairSync.lock();
final void lock() {
            //cas 0 -> 1 , 如果操作胜利,将以后线程设置为独占线程
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                // 如果操作失败
                acquire(1);
        }
    public final void acquire(int arg) {//tryAcquire(arg) 尝试获取锁,如果获取锁失败返回 false, 否则返回 true
        if (!tryAcquire(arg) &&
            // 尝试取得锁,如果以后线程被中断 返回 true, 否则返回 false
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            // 取得锁失败,且以后线程的中断状态为 true, 则从新去尝试
            selfInterrupt();}

tryAcquire() 最终默认调用 ReentrantLock.NonfairSync.nonfairTryAcquire();

        final boolean nonfairTryAcquire(int acquires) {
            // 获取以后线程
            final Thread current = Thread.currentThread();
            // 获取 state 值
            int c = getState();
            //0 代表没有线程占用锁
            if (c == 0) {
                //cas 将 0 改为 1
                if (compareAndSetState(0, acquires)) {
                    //cas 胜利之后 将独占线程改为以后线程
                    setExclusiveOwnerThread(current);
                    // 返回胜利
                    return true;
                }
            }
            // 如果有线程获取以后线程 (也就是以后线程是独占线程)
            else if (current == getExclusiveOwnerThread()) {
                //state 值加 1
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                // 保留新的 state 值
                setState(nextc);
                // 返回 true
                return true;
            }
            // 否则,就返回 false
            return false;
        }

AbstractQueuedSynchronizer.addWaiter(Node.EXCLUSIVE); 解析

    private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);
        // 尾节点赋值给 pred;Node pred = tail;
        // 尾节点不为空
        if (pred != null) {
            // 以后的节点 prev 指针指向当初的尾节点
            node.prev = pred;
            //cas 将以后尾节点 替换为 node 节点
            if (compareAndSetTail(pred, node)) {
                // 以后尾节点的 next 指针指向 node 节点
                pred.next = node;
                return node;
            }
        }
        // 如果尾节点为空或者 cas 替换失败,则执行入队操作
        enq(node);
        return node;
    }
    // 入队操作:将以后节点设置为尾节点,并更新以后节点和替换前的尾节点的指针指向
    private Node enq(final Node node) {for (;;) {
                // 把尾节点赋值给一个变量
                Node t = tail;
                // 如果尾节点为空
                if (t == null) {
                    // 新建一个节点,设置为头节点
                    if (compareAndSetHead(new Node()))
                        // 把头节点赋值尾节点
                        tail = head;
                } else {
                    // 如果尾节点不为空,以后节点的 prev 指针指向尾节点
                    node.prev = t;
                    //cas 将以后节点设置为尾节点
                    if (compareAndSetTail(t, node)) {
                        // 替换前的尾节点的 next 指针指向以后节点
                        t.next = node;
                        return t;
                    }
                }
                // 如果 cas 替换尾节点 失败,则循环执行,直到胜利为止
            }
      }

AbstractQueuedSynchronizer.acquireQueued(addWaiter(Node.EXCLUSIVE), arg);

// 曾经入队的非中断线程再次尝试获取锁
final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                // 获取以后节点的前一个节点信息
                final Node p = node.predecessor();
                // 如果前一个节点信息为头节点,并且胜利取得锁
                if (p == head && tryAcquire(arg)) {
                    // 设置以后节点为头节点
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    // 返回以后节点的线程中断状态
                    return interrupted;
                }
                // 如果以后节点的前驱节点不是头节点 或者 取得锁失败,则阻塞以后节点线程期待以后节点的线程被唤醒,并判断中断状态
                if (shouldParkAfterFailedAcquire(p, node) &&
                    // 阻塞以后线程,期待以后线程被唤醒后,判断以后线程的中断状态
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {if (failed)
                cancelAcquire(node);
        }
    }

shouldParkAfterFailedAcquire(p, node) 细节如下:

// 获取锁失败的线程查看并更新 node 中的 waitStatus。如果线程应该被阻塞返回 true。private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        // 获取前一个节点的期待状态
        int ws = pred.waitStatus;
        //-1,代表前一个节点被阻塞中, 须要唤醒
        if (ws == Node.SIGNAL)
            return true;
        if (ws > 0) {
            // > 0 代表前一个节点被勾销,就递归往找 waitStatus > 0 的节点信息
            do {node.prev = pred = pred.prev;} while (pred.waitStatus > 0);
            // 找到后,将此节点的 next 指针指向以后节点
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             * waitStatus 必须是 0 或者 -3(示意能够共享取得)。表明咱们须要唤醒,然而还没有阻塞。调用者须要重试去保障在阻塞操作之前不能获取胜利
             */
            //cas 将 前一个节点的 waitStatus 改为 -1(须要唤醒)compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        // 返回 false
        return false;
    }

    private final boolean parkAndCheckInterrupt() {
        // 阻塞以后线程
        LockSupport.park(this);
        // 以后线程被唤醒后,判断以后线程的的中断状态
        // 这里有一个十分重要的知识点:唤醒阻塞线程的形式 1.unpark 2.interrupt
        return Thread.interrupted();}

正文完
 0