J.U.C剖析与解读2(AQS的由来)

J.U.C剖析与解读2(AQS的由来) 前言

前面已经通过实现自定义ReentrantLock与自定义ReentrantReadWriteLock,展示了JDK是如何实现独占锁与共享锁的。

那么实际JDK源码中的ReentrantLock与ReentrantReadWritreLock是如何实现的呢?我们现有的自定义代码是否可以更进一步呢?

答案是肯定的。注意看我之前两个Lock的朋友,应该注意到了。自定义ReentrantReadWriteLock的独占锁部分,其实和自定义ReentrantLock是几乎一样的。

也就是说,不同Lock其实现是差不多的。那么是否可以提取公共的部分,是否可以写得更加优雅一些。

那么这篇博客,就是通过提取公共代码,引入模板方法设计模式,并利用Java的一些特性,写出一个自定义的AQS。

当然,最后也会剖析源码中AQS实现与我们自定义AQS的差别所在,并解读源码AQS中一些高级应用,如AQS通过一个state实现读写锁的持有数量(居然通过一个int值的CAS操作,解决了自定义读写锁持有数量的独占操作)。

如果看过源码的朋友,会发现源码中的ReentrantLock会自定义一个Sync,该Sync会继承一个AbstratQueueSynchronizer(简称AQS)。然后源码中的ReentrantLock的tryLock等方法,则是调用Sync的对应子类(FairSync或NonFairSync,也就是是否为公平锁)来实现对应功能。并且,只有tryAcquire与lock两个方法是由ReentrantLock实现的,其它方法是由AQS提供的。lock是由FairSync与NonFairSync分别实现的。而tryAcquire是由FairSync与NonFairSync父类的Sync实现,NonFairSync的tryLock直接调用父类Sync的nonfairTryAcquire方法。

而ReentrantReadWriteLock则是增加了ReadLock与WriteLock,其实现,则是调用Sync的不同方法而已。

有的小伙伴,会觉得这样的关系很复杂,明明一个锁就比较复杂了,还搞得这么抽象。提取一个AQS就够抽象的了,每个锁还整了一个Sync,FairSync,NonFairSync内部类,视情况,还要弄个ReadLock,WriteLock这些内部类。这样做的目的其实是为了封装代码,提高代码复用性。当然,实际源码看多了,反而会觉得这样的代码,看得挺舒服的。比较符合设计理念(想想,你接收的项目中,一个类上千行代码,完全不敢修改)。

关于读源码,简单说一下我的感受。最核心的就是坚持,最重要的是全局观,最需要的是积累。

我陆陆续续阅读源码(不只是Java),也有差不多两年的经验吧。从最早的Windows内核源码,到后面的前端框架源码,到今年的Java源码阅读。最早的Windows内核源码,那真的是无知者无畏啊,简直是一段极其痛苦的经历。那时候一天可能就二十页样子,还得看运气。但是那段时间给我带来了很多,包括什么系统内存管理,内存的用户态与内核态,以及系统上下文等积累,为我后面的提升带来了很多。而后面的前端源码的阅读,也让我开始接触源码的一些思路。最后到今年的Java源码,有了去年golang一些外文博客的翻译(涉及语言设计部分)铺垫,才渐渐有了一些阅读源码的感觉(自我感觉有点上路了)。所以,最核心的是坚持。

至于全局观嘛,就是一方面很多时候源码太多,常常迷路,我们需要把握主线,以及自己的目的。如果可以有一个XMIND,或者比较不错的博客等作为指引就更好了。比如这次AQS拆分,我就是从网易云的大佬James学到的。虽然之前就有了JUC学习的积累,但是大佬的AQS拆分,确实令我对AQS有了更为深入的理解。另一方面就是需要把握自己应该研究的深度(在自己能力层级再深入一些即可),而不是抓着源码的每个字不放。我今年年初的时候,就想研究IOC源码,根据一位大佬的文章,连续啃了两三个星期。但后面陆陆续续就忘了。虽然这段经历对我依旧有着一定的积累价值(对我最近研究SpringApplication的run过程有着不错的价值),但是超出自己能力太多地撸源码,性价比就太低了。

最后就是积累,我非常看重积累。自从高三后,我就对积累这个词有了更深入的理解。很多时候,我们阅读一些书籍,研究一些原理,虽然后来感觉忘记了,但是积累还是在的。就像我学习编程时,就经常感受到大学时期的计算机网络,计算机原理,分布式课题等经历给我带来的积累。而现在很多人都过于看重即时价值(就是我立马学了,立马就要有效果),而我相信技术的攀登,是离不开经年累月的积累的。

如果大家对阅读源码,感兴趣的话,可以告诉我。可以考虑写一篇文章,来简单谈谈源码阅读这件事儿。

一,简易JUC(版本一):

这里就是将之前实现的简易版ReentrantLock与ReentrantReadWriteLock展现出来,就当是简单回顾一下。

1.JarryReentrantLock: package tech.jarry.learning.netease.locks2; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.LockSupport; /** * @Description: 仿ReentrantLock,实现其基本功能及特性 * @Author: jarry */ public class JarryReentrantLock { private AtomicInteger count = new AtomicInteger(0); private AtomicReference<Thread> owner = new AtomicReference<>(); private LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>(); public void lock() { int arg = 1; if (!tryLock(arg)){ waiters.offer(Thread.currentThread()); while (true){ Thread head = waiters.peek(); if (head == Thread.currentThread()){ if (!tryLock(arg)){ LockSupport.park(); } else { waiters.poll(); return; } } else { LockSupport.park(); } } } } public void unlock() { int arg = 1; if (tryUnlock(arg)){ Thread head = waiters.peek(); if (head != null){ LockSupport.unpark(head); } } } public boolean tryLock(int acquires) { int countValue = count.get(); if (countValue != 0){ if (Thread.currentThread() == owner.get()){ count.set(countValue+acquires); return true; }else{ return false; } }else { if (count.compareAndSet(countValue,countValue+acquires)){ owner.set(Thread.currentThread()); return true; } else { return false; } } } private boolean tryUnlock(int releases) { if (Thread.currentThread() != owner.get()){ throw new IllegalMonitorStateException(); } else { int countValue = count.get(); int countNextValue = countValue - releases; count.compareAndSet(countValue,countNextValue); if (countNextValue == 0){ owner.compareAndSet(Thread.currentThread(),null); return true; } else { return false; } } } public void lockInterruptibly() throws InterruptedException { } public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return false; } public Condition newCondition() { return null; } } 2.JarryReadWriteLock: package tech.jarry.learning.netease.locks2; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.LockSupport; /** * @Description: * @Author: jarry */ public class JarryReadWriteLock { volatile AtomicInteger readCount = new AtomicInteger(0); AtomicInteger writeCount = new AtomicInteger(0); AtomicReference<Thread> owner = new AtomicReference<>(); public volatile LinkedBlockingQueue<WaitNode> waiters = new LinkedBlockingQueue<>(); class WaitNode{ Thread thread = null; // 表示希望争取的锁的类型。0表示写锁(独占锁),1表示读锁(共享锁) int type = 0; int arg = 0; public WaitNode(Thread thread, int type, int arg) { this.type = type; this.thread = thread; this.arg = arg; } } /** * 获取独占锁(针对独占锁) */ public void lock(){ int arg = 1; if (!tryLock(arg)){ WaitNode waitNode = new WaitNode(Thread.currentThread(), 0, arg); waiters.offer(waitNode); while (true){ WaitNode headNote = waiters.peek(); if (headNote !=null && headNote.thread == Thread.currentThread()){ if (!tryLock(headNote.arg)){ LockSupport.park(); } else { waiters.poll(); return; } }else { LockSupport.park(); } } } } /** * 解锁(针对独占锁) */ public void unlock(){ int arg = 1; if (tryUnlock(arg)){ WaitNode head = waiters.peek(); if (head == null){ return; } LockSupport.unpark(head.thread); } } /** * 尝试获取独占锁(针对独占锁) * @param acquires 用于加锁次数。一般传入waitNode.arg(本代码中就是1。为什么不用一个常量1,就不知道了?) * @return */ public boolean tryLock(int acquires){ if (readCount.get() == 0){ int writeCountValue = writeCount.get(); if (writeCountValue == 0){ if (writeCount.compareAndSet(writeCountValue,writeCountValue+acquires)){ owner.set(Thread.currentThread()); return true; } } else { if (Thread.currentThread() == owner.get()){ writeCount.set(writeCountValue+acquires); return true; } } } return false; } /** * 尝试解锁(针对独占锁) * @param releases 用于设定解锁次数。一般传入waitNode.arg * @return */ public boolean tryUnlock(int releases){ if (owner.get() != Thread.currentThread()){ throw new IllegalMonitorStateException(); } int writeCountValue = writeCount.get(); writeCount.set(writeCountValue-releases); if (writeCount.get() == 0){ owner.compareAndSet(Thread.currentThread(),null); return true; } else { return false; } } /** * 获取共享锁(针对共享锁) */ public void lockShared(){ int arg = 1; if (!tryLockShared(arg)){ WaitNode waitNode = new WaitNode(Thread.currentThread(),1,arg); waiters.offer(waitNode); while (true){ WaitNode head = waiters.peek(); if (head != null && head.thread == Thread.currentThread()){ if (tryLockShared(head.arg)){ waiters.poll(); WaitNode newHead = waiters.peek(); if (newHead != null && newHead.type == 1){ LockSupport.unpark(newHead.thread); } return; } else { LockSupport.park(); } } else { LockSupport.park(); } } } } /** * 解锁(针对共享锁) */ public boolean unLockShared(){ int arg = 1; if (tryUnLockShared(arg)){ WaitNode head = waiters.peek(); if (head != null){ LockSupport.unpark(head.thread); } return true; } return false; } /** * 尝试获取共享锁(针对共享锁) * @param acquires * @return */ public boolean tryLockShared(int acquires){ while (true){ if (writeCount.get() == 0 || owner.get() == Thread.currentThread()){ int readCountValue = readCount.get(); if (readCount.compareAndSet(readCountValue, readCountValue+acquires)){ return true; } } return false; } } /** * 尝试解锁(针对共享锁) * @param releases * @return */ public boolean tryUnLockShared(int releases){ while (true){ int readCountValue = readCount.get(); int readCountNext = readCountValue - releases; if (readCount.compareAndSet(readCountValue,readCountNext)){ return readCountNext == 0; } } } } 二,简易JUC(版本二):

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzxzzz.html