ReentrantLock
ReentrantLock 即可重入锁,有 3 个内部类:Sync、FairSync 和 NonfairSync。
- Sync 是一个继承 AQS 的抽象类,并发控制就是通过 Sync 实现的。
- 有两个子类 FiarSync 和 NonfairSync,即公平锁和非公平锁。
ReentrantLock构造器,默认是非公平锁
private final Sync sync;public ReentrantLock() { //默认是非公平锁sync = new NonfairSync();}public ReentrantLock(boolean fair) { //可设置为公平锁sync = fair ? new FairSync() : new NonfairSync();}
ReentrantLock 加锁
ReentrantLock加锁会根据是公平锁还是非公平锁调用不同方法
lock方法的过程(分为公平和非公平)
非公平锁会先进行一次CAS操作,去抢占自由状态的锁,若此时锁为非自由状态,则会进行同公平锁一致取锁操作
// 非公平锁 NonfairSyncfinal void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}// 公平锁final void lock() {acquire(1);}
进入acquire方法
public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}
进入tryAcquire方法,该方法内对于自由状态下的公平锁和非公平锁有区别,对于重入锁一致
//公平锁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;}//非公平锁protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}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) // overflowthrow new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
- 获取锁状态,若state=0自由状态
- 非公平锁进行一次CAS操作取锁,成功返回true
- 公平锁会进行判断等待队列是否为空,不为空则判断当前线程是否是队头,若是,进行一次CAS操作取锁,成功返回true
- state!=0,锁为非自由状态
- 判断当前线程是否为持有锁线程,若是则计入重入数,且取锁true,否则false
取锁失败后,入队addWaiter
private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);// Try the fast path of enq; backup to full enq on failureNode pred = tail;if (pred != null) {node.prev = pred;if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}enq(node);return node;}private Node enq(final Node node) {for (;;) {Node t = tail;if (t == null) { // Must initializeif (compareAndSetHead(new Node()))tail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {t.next = node;return t;}}}}
- 队尾不为空,即队列不为空,将线程装node存在队尾,入队结束
- 队尾为空,即队列为空,为队列进行初始化,将线程装node存在队尾,入队结束
入队后,acquireQueued
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 GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {int ws = pred.waitStatus;if (ws == Node.SIGNAL)/** This node has already set status asking a release* to signal it, so it can safely park.*/return true;if (ws > 0) {/** Predecessor was cancelled. Skip over predecessors and* indicate retry.*/do {node.prev = pred = pred.prev;} while (pred.waitStatus > 0);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.*/compareAndSetWaitStatus(pred, ws, Node.SIGNAL);}return false;}
- 判断当前node前一个节点是否队头节点,队头节点是线程为空的节点
- 若是,则将其设为头节点,进行取锁,且未被中断
- 若不是,则进入shouldParkAfterFailedAcquire
- 如果当前节点的前置节点的waitstatus为SIGNAL,说明前置节点也在等待拿锁,所以当前节点是可以挂起的,睡眠当前线程,返回中断状态,若当前线程被中断了,则将当前节点设置为取消节点,并清除多余的取消节点
- 如果waitStatus状态是CANCEL,往前搜索,直至搜索到waitStatus<=0,填在其后面,中间部分直接删除
- waitStatus是其他状态,既然当前节点已经加入,那么前置节点就应该做好等待锁的准备,所以将前置节点waitStatus置为SIGNAL,若会再循环一次,将当前节点挂起
ReentrantLock 解锁
非公平锁和公平锁解锁的操作是一致的
当调用unlock解锁的时候
sync.release(1); 进入release方法
public void unlock() {sync.release(1);}public final boolean release(int arg) {if (tryRelease(arg)) {Node h = head;if (h != null && h.waitStatus != 0)unparkSuccessor(h);return true;}return false;}
tryRelease
- 把锁的状态改为自由状态
- 解锁的线程和持有的线程不一样,会抛出异常。这种情况一般不会出现,除非你没有加锁直接解锁则会异常
- boolean free = false; 标识一下目前还没有释放锁成功,因为你仅仅把锁改成了自由状态,线程没有释放(而且还有可能是重入),所以这个变量是一个过渡变量
- c == 0释放锁,返回true
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;}
锁被成功释放后,Node h = head;//拿到对头,if (h != null && h.waitStatus != 0);//判断是否有对头(是否有人在排队),若有节点在排队唤醒头节点
Sync
abstract static class Sync extends AbstractQueuedSynchronizer {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) // overflowthrow 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;}}
- Sync 重写了 tryRelease() 释放锁
- Sync 重写 tryRealese() 方法,并且 FairSync 和 NonfairSync没有再次重写该方法,所以 公平锁和非公平锁释放锁的操作是一样的,即唤醒等待队列中第一个被挂起的线程。
- 公平锁和非公平锁获取锁的方式是不同的。
- 公平锁获取锁时,如果一个线程已经获取了锁,其他线程都会被挂起进入先进先出等待队列,(即后面来的线程等待的时间没有等待队列中线程等待的时间长的话,那么就会放弃获取锁,直接进入等待队列)
- 非公平锁获取锁的方式是一种抢占式的,不考虑线程等待时间,无论是哪个线程获取了锁,则其他线程就进入等待队列。
- 非公平锁取锁
nonfairTryAcquire的方法出现在了父类Sync里,是因为 ReentrantLock 继承了Lock接口,Lock接口里面的tryLock方法同样需要这个非公平锁取锁的步骤
nonfairTryAcquire(int acquires)
非公平取锁
- getState获得锁状态,若state=0为自由状态,进行一次CAS操作获得锁
- 若state!=0,即为非自由状态,且当前线程为持有锁线程,即重入,state+acquires
- 以上取锁成功,返回true,失败则false
tryRelease(int releases)
公平锁,非公平锁释放锁
- getState获得锁状态-releases需要释放的次数,若当前线程为非持有锁线程,抛出异常
- 若释放锁后的state=0,表示自由状态,将持有锁对象设置=null,且返回true,否则false
FairSync
公平锁
static final class FairSync extends Sync {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;}}
NonfairSync
非公平锁
static final class NonfairSync extends Sync {final void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}}
