Java ReentrantLock 简介

一、概述

ReentrantLock是一个可重入锁。具有公平性和非公平性两种模式。

可重入:如果当前线程已经获取到锁了,在再次获取的时候可以对共享资源重复加锁,不需要重新排队即可获取到。

公平锁:线程获取锁必须按照FIFO的模式排队获取,先到先得。

非公平锁:允许队列后面的线程先获取锁。

二、ReentrantLock的相关属性与构造方法

Sync sync:ReentrantLock中仅有的一个属性

默认非公平锁的构造方法

public ReentrantLock() {
        sync = new NonfairSync();
    }

可以设置为公平锁的构造方法:

public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

从上面两个方法可以看到在ReentrantLock中是存在NonfairSync、FairSync、Sync这三个对象的。这三个对象是怎么一回事?接着往下看ReentrantLock的源码:

package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
import java.util.Collection;

public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;
    /** Synchronizer providing all implementation mechanics */
    private final Sync sync;

    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        abstract void lock();

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

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // Methods relayed from outer class

        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

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

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

    /**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

}

从上述代码中可见ReentrantLock是存在三个内部类的,也就是说上面提到的三个对象都是ReentrantLock的内部类。其中Sync继承了AbstractQueuedSynchronizer类(AQS),NonfairSync和FairSync都继承了Sync的。

所以公平锁是让FairSync构建sync对象,非公平锁是让NonfairSync构建sync对象。线程在AbstractQueuedSynchronizer中是保存在 Node 对象中的。

三、可重入的实现

先看代码

/**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            // 获取贡献资源的上锁次数
            int c = getState();
            // 如果没有被上锁
            if (c == 0) {
                // 通过CAS获取同步状态,获取锁
                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;
        }

上述代码中的第二个条件分支,如果当前执行线程等于获取到锁的线程,则证明是同一条线程,则获取到锁的次数相加,就是同一条线程再次获得了锁,实现了重入。锁被多次获取也就会被多次释放,只有释放到state等于0时,才能完全释放锁。

四、锁的获取

公平锁的获取:

公平锁通过当前线程是否是队列中的head和当前线程是否是已经获取到锁的线程作为依据 来判断当前线程是否能够获取到锁。如果符合条件,则将AQS中的独享线程设置为当前线程。否则假如等待队列。

final void lock() {
            acquire(1);
        }
protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            // 获取状态
            int c = getState();
            // 未上锁
            if (c == 0) {
                // 判断当前线程是否是head,如果是,通过 CAS 获取锁
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    // 将独享线程设置为当前线程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            // 判断当前线程是否是已经获得锁的线程,如果是,则重入
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            // 不是则返回 
            return false;
        }

否则加入等待队列,当前线程状态设置为阻塞

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;
    }
static void selfInterrupt() {
        Thread.currentThread().interrupt();
    }

非公平锁的获取:

和公平锁的获取差不多

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

在state为0时,非公平锁比公平锁少了一个获取到锁的条件,不要求线程是队列中的head。

五、锁的释放

protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

参考博客:https://juejin.im/post/5aeb0a8b518825673a2066f0

参考博客:https://www.cnblogs.com/iou123lg/p/9535710.html

参考博客:https://tech.meituan.com/2019/12/05/aqs-theory-and-apply.html

建议去看上面的三个参考博客。

你可能感兴趣的:(多线程)