版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012031408/article/details/88717741
ReentrantLock是一个显示锁,实现基础都是AQS。所谓的AQS就是AbstractQueuedSynchronizer,
AQS的作用
- 用来构建锁和同步工具的框架, ReentrantLock、CountDownLatch、Semaphore基础都是AQS
- AQS有个state变量,是int类型,使用了volatile修饰,AQS围绕state提供两种基本的获取和释放功能
ReentrantLock分析
- 在ReentrantLock中定义了一个抽象的静态类Sync,该类继承了AbstractQueuedSynchronizer
- ReentrantLock中还定义了公平锁和非公平锁(FairSync/NonfairSync),这两个锁继承了Sync。
- 公平锁:线程获取锁的顺序和调用lock的顺序一样,FIFO先进先出
- 非公平锁:线程锁获取所得顺序和调用lock的顺序无关,随机的
- ReentrantLock默认是实现非公平锁
非公平锁
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
也同时提供使用公平锁了形参构造器方法来
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
- 如何获取锁获取锁
- ReentrantLock提供lock()方法,该方法直接使用的是Sync类中的lock方法,该方法是个抽象方法,因为ReentrantLock默认是非公平锁,所以lock()方法的具体实现在NonfairSync中的lock()中
final void lock() {
//判断当前state是否是0,如果是0,则将值设为1,并将当前线程设为独占锁线程
//否则
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
//如果当前state不是0,则当前线程放入等待队列
acquire(1);
}
//调用AbstractQueuedSynchronized类中的acquire()来中断
public final void acquire(int arg) {
//调用NonfairSync非公平锁类的tryAcquire()方法
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
//使用addWaiter()方法创建一个Node,同时给一个类型
//将线程加入阻塞队列
//Node.EXCLUSIVE for exclusive, Node.SHARED for shared
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Tail of the wait queue, lazily initialized. Modified only via method enq to add new wait node.
// tail是等待队列的尾部,延迟初始化,通过enq()方法添加节点
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
//enq方法是一个死循环(是为了保证Node一定能插入队列),当队列为空时,会创建一个空的Node作为head节点
enq(node);
return node;
}
//不间断的获取已经在队列中的独占线程
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);
}
}
shouldParkAfterFailedAcquire(Node pred, Node node)该方法的作用是检查和更新获取失败的节点的状态。如果线程要阻塞就返回true
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
//如果前一个节点的状态是SIGNAL,阻塞,返回true
return true;
if (ws > 0) {
// 如果前一个节点的状态是CANCELLED,则跳过所有前置任务(通过循环将前面的节点都移除)
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//如果是其他状态,则都将状态更新为SIGNAL
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
final boolean nonfairTryAcquire(int acquires) {
//获取当前线程
final Thread current = Thread.currentThread();
//获得AQS的state是否等于0,等于0表示没有人占有
int c = getState();
if (c == 0) {
// 然后比较并更新state,如果state是0,就把值设为1
if (compareAndSetState(0, acquires)) {
// 当前线程获取锁,并设置线程拥有独占访问权,即获得独占锁
setExclusiveOwnerThread(current);
return true;
}
}
//判断当前线程是否是独占锁线程,因为ReentrantLock是可重入的,线程可以不停的lock来增加state的值,对应的就需要unlock来解锁,直到state为0
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;
}
- 锁的释放
- ReentrantLock提供了unlock()方法,该方法中调用了Sync中的release方法。sync.release(1);入参写死为1,因为每当一个线程获取到独占线程时,都会把自己设为head.
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
//唤醒头节点的下一个节点
unparkSuccessor(h);
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;
}