并发编程艺术--AQS底层源码解析(三)
本章我们继续AQS的源码解析,ReentrantLock本身是重入锁,之前解析了很多关于ReentrantLock的源码但是可重入锁这部分却没有谈及接下来讲一下重入锁是如何实现的。
可重入锁:
对于ReentrantLock的可重入锁的具体实现逻辑是在tryAcquire这个方法中实现的,本身AQS是没有这个方法的具体业务逻辑的交给子类去实现的而ReentrantLock中的Sync继承了AQS并且去实现了tryAcquire,在tryAcquire方法中定义了如何处理重入锁的逻辑。
protected final boolean tryAcquire(int var1) {Thread var2 = Thread.currentThread();int var3 = this.getState();if (var3 == 0) {if (!this.hasQueuedPredecessors() && this.compareAndSetState(0, var1)) {this.setExclusiveOwnerThread(var2);return true;}} else if (var2 == this.getExclusiveOwnerThread()) {int var4 = var3 + var1;if (var4 < 0) {throw new Error("Maximum lock count exceeded");}this.setState(var4);return true;}return false;}
两个if条件判断分别是判断锁是否被占用,然后判断当前线程持有锁线程是否为本线程。
第一个判断的内部逻辑主要是公平锁校验的(这个后续会说),第二个则是可重入锁判定的
getExclusiveOwnerThread方法返回值是当前持有锁的线程对象,与本线程对象进行比对如果是同一个对象则证明当前是重入锁逻辑操作将state状态变量进行加一。
可以看出每次重入锁的时候都会将state同步量加一,这样就能对其锁的重入次数进行技术,那么每次释放锁的时候都会进行减一直到最后为0的时候才会真正的释放锁。顺带我们看一下释放锁的过程。释放锁则是tryRelease方法来实现的。
protected final boolean tryRelease(int var1) {int var2 = this.getState() - var1;if (Thread.currentThread() != this.getExclusiveOwnerThread()) {throw new IllegalMonitorStateException();} else {boolean var3 = false;if (var2 == 0) {var3 = true;this.setExclusiveOwnerThread((Thread)null);}this.setState(var2);return var3;}}
首先将状态值扣减,并且进行判断如果状态值为0则释放锁,将当前持有锁的线程置为null,然后设置状态值,最后返回boolean类型值表示是否完成了锁释放。
公平锁和非公平锁:
如果一个锁是公平的那么获取资源的顺序就应该满足FIFO队列中的顺序,否则则不为公平锁。公平锁能尽可能的减少线程饥饿,但是相比于非公平锁的性能则会差不少。
前面代码中hasQueuedPredecessors则是公平锁的校验代码
public final boolean hasQueuedPredecessors() {Node var1 = this.tail;Node var2 = this.head;Node var3;return var2 != var1 && ((var3 = var2.next) == null || var3.thread != Thread.currentThread());}
主要业务逻辑是查看是否队列前面是否有其他线程在等待,如果有则返回false,借此来进行公平锁校验
对于非公平锁则是通过nonfairTryAcquire来进行
final boolean nonfairTryAcquire(int var1) {Thread var2 = Thread.currentThread();int var3 = this.getState();if (var3 == 0) {if (this.compareAndSetState(0, var1)) {this.setExclusiveOwnerThread(var2);return true;}} else if (var2 == this.getExclusiveOwnerThread()) {int var4 = var3 + var1;if (var4 < 0) {throw new Error("Maximum lock count exceeded");}this.setState(var4);return true;}return false;}
可以看出非公平锁与公平锁的区别就在于当判断到资源没有被占用的时候,公平锁则是再判断一下是否该到自己了,而非公平锁则是直接进行CAS占有锁操作。
对于ReentrantLock来说默认是非公平锁。
下一章节我们将来介绍LockSupport阻塞线程工具类,以及Condition基于等待队列的线程唤醒与等待工具类