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操作,去抢占自由状态的锁,若此时锁为非自由状态,则会进行同公平锁一致取锁操作
// 非公平锁 NonfairSync
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(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) // overflow
throw 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 failure
Node 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 initialize
if (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 GC
failed = 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) // 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;
}
}
- 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());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}