【Java】ReentrantLock.lock流程

相关方法流程

1. ReentrantLock.lock

    public void lock() {
        sync.lock();
    }

ReentrantLock.lock会调用sync.lock,当锁为非公平锁时,sync的类型为ReentrantLock.NonfairSync

2. NonfairSync.lock

    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

这里首先会尝试使用CAS将状态从0改变到1(在这里,状态0表示当前没有线程持有这个锁);如果成功,则表示获取锁成功,将占有锁线程设置为当前线程;如果失败,则调用acquire(1)方法。

3. AQS.acquire

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
        // NonfairSync
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }

        // 在先不考虑线程重入的情况下,这个方法就是使用CAS将当前状态值从0修改为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()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

首先尝试使用tryAcquire获取锁。由于刚才已经获取失败,所以这里会返回false。重点看acquireQueued(addWaiter(Node.EXCLUSIVE), arg)这里。

4. AQS.acquireQueued

    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;
            }
        }
        enq(node);
        return node;
    }

    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);
        }
    }

addWaiter很简单,就是将当前线程加入到等待队列中。
acquireQueued则是调用tryAcquire方法。如果获取失败,则阻塞(park)直到下一次被唤醒,依此无限循环。

总结

ReentrantLock类中持有一变量sync,即同步器,这是一个继承自AQS的Sync类型的变量。在类型为非同步锁的情况下,这个对象的真实类型为NonfairSync
sync对象保存了当前同步器的状态(0为无线程持有锁),以及当前持有锁的线程。

  1. 在调用ReentrantLock.lock后,首先会尝试将sync的状态从0改为1。
  2. 如果成功,则设置持有线程为当前线程并返回,加锁成功。
    如果失败,则再次尝试修改状态(如果state为0则尝试修改为1,如果state不为0且持有线程为当前线程,则state++);若再次失败,则将当前线程加入等待队列。加入等待队列之后,会再尝试获取锁,如果失败,则挂起(park)该线程。
  3. 在锁被释放时,会唤醒等待队列中的第一个线程,使其尝试竞争锁(和处于前2步的线程竞争)。如果失败,则再将其挂起直到下一次被唤醒。

相关参考

一张图读懂非公平锁与公平锁

你可能感兴趣的:(【Java】ReentrantLock.lock流程)