实现了Lock接口
内部也维护了一个同步器Sync继承自AQS,Sync是抽象的,两个实现NonFairSync和FairSync
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
非公平锁加锁解锁流程
// 加锁
CAS修改State状态0->1
修改成功,则将Owner线程设置为当前线程
修改失败
调用AQS中的acquire方法
public final void acquire(int arg) {
if (!tryAcquire(arg) && // 再次尝试获取锁
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
获取失败,addWaiter将当前线程封装为一个Node对象,加入到等待的双向Node链表中
进入acquireQueued逻辑
acquireQueued会在一个死循环中不断尝试获得锁,失败后park阻塞
1.如果是紧邻着head(head指向的Node节点的下一个Node节点),那么可以再次tryAcquire尝试获取锁,当然这时state仍为1,失败
2.进入shouldParkAfterFailedAcquire逻辑,将前驱node,即head的waitStatus改为-1,这次返回false
3.当再次进入shouldParkAfterFailedAcquire时,这时因为其前驱node的waitStatus已经是-1,这次返回true
4.进入parkAndCheckInterrupt,阻塞
// 解锁
调用了AQS的release方法
public final boolean release(int arg) {
// tryRelease中将OwnerThread设置为null,将state设置为0
if (tryRelease(arg)) { // 调用ReentrantLock中Sync内部类的tryRelease方法
Node h = head; // 看head的指向是否为null以及waitstatus
if (h != null && h.waitStatus != 0)
unparkSuccessor(h); // 找到等待链表中离head最近的一个Node(没取消的),unpark恢复其运行
return true;
}
return false;
}
// 线程被唤醒后
final boolean acquireQueued(final Node node, int arg) {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) { // 唤醒后恢复运行拿到锁
setHead(node); // 将head指向为自己的Node节点,自己的Node节点也不再关联线程
p.next = null; // help GC,将之前head指向的Node节点断开
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node))
interrupted |= parkAndCheckInterrupt(); // 获取锁时,是在这里被park阻塞的,所以也从这里恢复运行
}
}
非公平锁,当释放锁的时候,又来了一个线程,会和刚被唤醒的线程竞争
被唤醒的线程没竞争过,则又会park,去睡觉
可重入原理
获取锁时,如果state已经为1,会判断当前线程是不是Owner线程
如果是,表示发生了锁重入,会让state++
释放锁时调用tryRelease方法,会让state减1,减完之后发现不是0,则返回false,不会释放锁
只有当state减完之后变为0了,才会释放锁,返回true
可打断原理
默认是不可打断的,因为被打断后恢复运行,会继续尝试获得锁,获得到会将打断标记true作为结果返回,获得不到会继续阻塞
final boolean acquireQueued(final Node node, int arg) {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return interrupted; // 获取锁时,会将打断标记作为结果返回
}
if (shouldParkAfterFailedAcquire(p, node))
// 被打断唤醒后会将打断标记清除(为了下面获取锁失败时还可以park住),将true赋给interrupted
interrupted |= parkAndCheckInterrupt();
}
}
// 这里acquireQueued返回true,表示是被打断后恢复运行拿到了锁
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// 这里会重新设置打断标记,因为之前清理了打断标记
selfInterrupt();
}
可打断(使用另一个获取锁的方法),打断唤醒后,会直接抛出异常,不会再尝试获取锁
公平锁原理
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;
}
}
// 判断当前线程是不是Owner线程
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
// java.util.concurrent.locks.AbstractQueuedSynchronizer#hasQueuedPredecessors
public final boolean hasQueuedPredecessors() {
Node h, s;
if ((h = head) != null) { // head是否为null
if ((s = h.next) == null || s.waitStatus > 0) {
s = null; // traverse in case of concurrent cancellation
for (Node p = tail; p != h && p != null; p = p.prev) {
if (p.waitStatus <= 0)
s = p;
}
}
// 如果有head指向的Node节点的下一个Node节点,且关联的线程不是自己
// 则自己就不要去竞争锁了
if (s != null && s.thread != Thread.currentThread())
return true;
}
return false;
}
条件变量实现原理
每个条件变量对应着一个等待链表,实现类是ConditionObject,维护了一个双向链表
await流程
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();// 创建Node对象,添加到等待链表中.Adds a new waiter to wait queue.
long savedState = fullyRelease(node);// 释放锁,唤醒AQS等待链表中的一个Node节点
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this); // 阻塞住
}
}
signal流程
先检查当前线程是不是锁的持有者,不是则抛出异常
将ConditionObject维护的等待链表中的第一个Node节点移除,转移到AQS的等待链表中