1、ReentrantLock的几个特点
- 可中断
- 可以设置超时时间
- 可以设置为公平锁
- 支持多个条件变量
- 与 synchronized 一样,都支持可重入
2、AQS原理
AQS内部主要维护了一个双向队列和一个状态state
在独占模式中,双向队列存储了所有阻塞的节点(当然也有被取消的节点)
节点存储了当前线程,每个节点也有几个状态,其中
- 1表示节点被取消
- -1表示该节点后面的节点需要被唤醒
- -2表示节点在条件变量中
AQS中的state变量的几个状态
- 0表示无锁
- 1表示有锁
- 大于1表示可重入锁
3、ReentrantLock的加锁流程
先看大概的加锁流程,以独占式不可中断锁为例。
final void lock() {
//cas尝试获取锁
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
//获取锁失败,则进入下面acquire
else
acquire(1);
}
//以独占模式获取,忽略中断
public final void acquire(int arg) {
//再一次尝试获取锁
if (!tryAcquire(arg) && //下面第一个方法
//获取锁失败则加入到队列中,并阻塞等待,直到获取到锁
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //下面方法(2)(3)
//如果途中被中断,则设置线程为中断状态,因为之前线程被中断后又取消了中断标记。
selfInterrupt();
}
tryAcquire(arg)->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;
}
//(2)将线程节点添加到AQS中阻塞队列的尾节点后面
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//添加失败,则在循环中重试,直到添加成功
enq(node); //下面第一个方法
return node;
}
//将线程节点添加到AQS中阻塞队列的尾节点后面
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { //保证有一个头节点,该节点不存储任何线程,相当于哨兵
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
//(3)在阻塞队列中一直阻塞,直到获取到锁
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()) //下面方法(4)
//即使被中断,也只是改变中断状态,仍然在循环中再次尝试获取锁
interrupted = true;
}
} finally {
//取消节点,比如被中断或者调用tryLock(time),在一定时间内没获取到锁则直接退出,不再竞争锁
if (failed)
//将当前线程节点从阻塞队列中移除
cancelAcquire(node);
}
}
//取消节点,比如被中断或者调用tryLock(time)
private void cancelAcquire(Node node) {
if (node == null)
return;
node.thread = null;
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
Node predNext = pred.next;
//修改状态
node.waitStatus = Node.CANCELLED;
//如果该节点是尾节点则将前一个节点设置为尾节点
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
} else {
int ws;
//前驱节点不是头节点
if (pred != head &&
//并且前驱节点没有被取消
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
//将该节点从阻塞队列中删除
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
//如果是前驱节点是头节点,唤醒后面的节点
unparkSuccessor(node);
}
node.next = node; // help GC
}
}
/*(4)检查和更新未能获取锁的节点的状态。 如果线程应该阻塞,则返回 true。这里需要理Node
中waitStatus的几种状态。在独占模式中,1表示线程已经被取消,-1(SIGNAL)表示后继线程需
要unpark,创建的新节点默认为0。*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true;
//表示该节点已经被取消,需要删除节点
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
//这里Node.SIGNAL表示要唤醒后继的线程的标识
} else {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
4、ReentrantLock的解锁流程
public final boolean release(int arg) {
//解锁
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h); //唤醒后面的节点,下面的方法(1)
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;
}
//(1)唤醒后面的节点
private void unparkSuccessor(Node node) {
// 如果状态为 Node.SIGNAL 尝试重置状态为 0
// 不成功也可以
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
//找到需要unpark的节点
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
5、锁超时
//以独占定时模式获取锁
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
final long deadline = System.nanoTime() + nanosTimeout;
//加入到阻塞队列中
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
//与上面acquireQueued方法类似,只是指定了阻塞时间
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
//被打断或者时间到了则取消节点
if (failed)
cancelAcquire(node);
}
}
6、锁可中断
//以独占模式获取,如果中断则中止
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//中断后直接抛异常。可以类比acquireQueued方法,acquireQueued方法中只是改变中断状态
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
7、公平锁&非公平锁
//NonfairSync非公平锁的的实现
final void lock() {
//每次lock会尝试去获取锁
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
public final void acquire(int arg) {
//尝试获取锁
if (!tryAcquire(arg) &&
//添加到AQS队列中阻塞
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
//tryAcquire->nonfairTryAcquire
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;
}
//FairSync非公平锁
final void lock() {
acquire(1);
}
//acquire->tryAcquire
//非公平锁的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;
}
8、可重入
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()) {
//将state加1
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}