ReentrantLock原理
实现了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设置为0if (tryRelease(arg)) { // 调用ReentrantLock中Sync内部类的tryRelease方法Node h = head; // 看head的指向是否为null以及waitstatusif (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 GCreturn interrupted; // 获取锁时,会将打断标记作为结果返回}if (shouldParkAfterFailedAcquire(p, node))// 被打断唤醒后会将打断标记清除(为了下面获取锁失败时还可以park住),将true赋给interruptedinterrupted |= 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是否为nullif ((s = h.next) == null || s.waitStatus > 0) {s = null; // traverse in case of concurrent cancellationfor (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的等待链表中