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(版本二):
很明顯,上面的代碼中,JarryReentrantLock的tryLock等方法與JarryReadWriteLock中共享鎖的tryLock等方法是類似的(本來就是從JarryReentrantLock復制過來的嘛)。那么,這里就需要引入模板方法(詳見筆記《設計模式》-模板方法)。通過一個commonMask類,來提取公共方法。
1.CommonMask:
package tech.jarry.learning.netease.locks3;
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 CommonMask {
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;
}
}
}
}
2.JarryReentrantLock:
package tech.jarry.learning.netease.locks3;
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 CommonMask commonMask = new CommonMask();
public void lock() {
commonMask.lock();
}
public void unlock() {
commonMask.unlock();
}
public boolean tryLock(int acquire) {
return commonMask.tryLock(acquire);
}
private boolean tryUnlock(int release) {
return commonMask.tryUnlock(release);
}
}
3.JarryReadWriteLock:
package tech.jarry.learning.netease.locks3;
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 {
private CommonMask commonMask = new CommonMask();
/**
* 獲取獨占鎖(針對獨占鎖)
*/
public void lock(){
commonMask.lock();
}
/**
* 解鎖(針對獨占鎖)
*/
public void unlock(){
commonMask.unlock();
}
/**
* 嘗試獲取獨占鎖(針對獨占鎖)
* @param acquires 用於加鎖次數。一般傳入waitNode.arg(本代碼中就是1。為什么不用一個常量1,就不知道了?)
* @return
*/
public boolean tryLock(int acquires){
return commonMask.tryLock(acquires);
}
/**
* 嘗試解鎖(針對獨占鎖)
* @param releases 用於設定解鎖次數。一般傳入waitNode.arg
* @return
*/
public boolean tryUnlock(int releases){
return commonMask.tryUnlock(releases);
}
/**
* 獲取共享鎖(針對共享鎖)
*/
public void lockShared(){
commonMask.lockShared();
}
/**
* 解鎖(針對共享鎖)
*/
public boolean unLockShared(){
return commonMask.unLockShared();
}
/**
* 嘗試獲取共享鎖(針對共享鎖)
* @param acquires
* @return
*/
public boolean tryLockShared(int acquires){
return tryLockShared(acquires);
}
/**
* 嘗試解鎖(針對共享鎖)
* @param releases
* @return
*/
public boolean tryUnLockShared(int releases){
return commonMask.tryUnLockShared(releases);
}
}
到了這里,大家就可以明顯看出,總體代碼量的下降(這還只是兩個Lock)。但是問題也出來了,那就是這樣將所有方法都放在父類CommonMask,子類進行調用,是不是顯得過於死板(說得直接點,就是這種操作,完全就是將代碼往父類一拋而已)。這說明,之前代碼公共提取做得並不好。
重新整理思路,JarryReentrantLock與JarryReadWriteLock的共同之處到底在哪里。細想一下,發現這兩個方法的lock,unlock等操作是一致的,只是實際的運行邏輯方法tryLock,tryUnlock,tryLockShared,tryUnLockShared四個方法(在框架源碼中,常常用doxxx方法,表示實際運行邏輯的方法)。所以CommonMask應該實現的是這四個方法之外的方法,而這四個方法交由子類,來根據具體需要來實現(CommonMask中,這四個方法直接拋出對應異常)。
最后,ReentrantLock是有公平鎖,非公平鎖之分的。而通過上面的調整,現在的JarryReentrantLock可以實現自己對應方法,來展現特性(公平鎖/非公平鎖的選擇)了。
三,簡易JUC(版本三):
1.CommonMask:
package tech.jarry.learning.netease.locks4;
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 CommonMask {
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);
}
}
/**
* 獲取共享鎖(針對共享鎖)
*/
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 tryLock(int acquires){
throw new UnsupportedOperationException();
}
/**
* 嘗試解鎖(針對獨占鎖)
* @param releases 用於設定解鎖次數。一般傳入waitNode.arg
* @return
*/
public boolean tryUnlock(int releases){
throw new UnsupportedOperationException();
}
/**
* 嘗試獲取共享鎖(針對共享鎖)
* @param acquires
* @return
*/
public boolean tryLockShared(int acquires){
throw new UnsupportedOperationException();
}
/**
* 嘗試解鎖(針對共享鎖)
* @param releases
* @return
*/
public boolean tryUnLockShared(int releases){
throw new UnsupportedOperationException();
}
}
2.JarryReentrantLock:
package tech.jarry.learning.netease.locks4;
/**
* @Description: 仿ReentrantLock,實現其基本功能及特性
* @Author: jarry
*/
public class JarryReentrantLock {
private boolean isFair;
// 默認采用非公平鎖,保證效率(就是參照源碼)
public JarryReentrantLock() {
this.isFair = false;
}
public JarryReentrantLock(boolean isFair) {
this.isFair = isFair;
}
private CommonMask commonMask = new CommonMask(){
@Override
public boolean tryLock(int acquires){
if (isFair){
return tryFairLock(acquires);
} else {
return tryNonFairLock(acquires);
}
}
private boolean tryFairLock(int acquires){
// 這里簡單注釋一下,如何實現公平鎖,其關鍵在於新的線程到來時,不再直接嘗試獲取鎖,而是直接塞入隊列(隊列為空,也是殊途同歸的)
// 1.判斷讀鎖(共享鎖)是否被占用
if (readCount.get() == 0){
// 2.判斷寫鎖(獨占鎖)是否被占用
int writeCountValue = writeCount.get();
if (writeCountValue == 0){
// 2.1 (核心區別)如果寫鎖未被占用,需要先對等待隊列waiters進行判斷
WaitNode head = waiters.peek();
if (head !=null && head.thread == Thread.currentThread()){
if (writeCount.compareAndSet(writeCountValue,writeCountValue+acquires)){
owner.set(Thread.currentThread());
return true;
} // 競爭失敗就直接返回false了
}
} else {
// 2.2 如果寫鎖已經被占用了,就判斷是否為當前線程持有,是否進行重入操作
if (owner.get() == Thread.currentThread()){
// 如果持有獨占鎖的線程就是當前線程,那么不需要改變owner,也不需要CAS,只需要修改writeCount的值即可
writeCount.set(writeCountValue + acquires);
return true;
}
}
}
// 以上操作失敗,就返回false,表示競爭鎖失敗
return false;
}
private boolean tryNonFairLock(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;
}
@Override
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;
}
}
// 其它諸如共享鎖的相關操作,就不進行了。如果強行調用,只會發生UnsupportedOperationException
};
public void lock() {
commonMask.lock();
}
public void unlock() {
commonMask.unlock();
}
public boolean tryLock(int acquire) {
return commonMask.tryLock(acquire);
}
private boolean tryUnlock(int release) {
return commonMask.tryUnlock(release);
}
}
3.JarryReadWriteLock:
package tech.jarry.learning.netease.locks4;
/**
* @Description:
* @Author: jarry
*/
public class JarryReadWriteLock {
private CommonMask commonMask = new CommonMask(){
@Override
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;
}
@Override
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;
}
}
@Override
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;
}
}
@Override
public boolean tryUnLockShared(int releases) {
while (true){
int readCountValue = readCount.get();
int readCountNext = readCountValue - releases;
if (readCount.compareAndSet(readCountValue,readCountNext)){
return readCountNext == 0;
}
}
}
};
/**
* 獲取獨占鎖(針對獨占鎖)
*/
public void lock(){
commonMask.lock();
}
/**
* 解鎖(針對獨占鎖)
*/
public void unlock(){
commonMask.unlock();
}
/**
* 嘗試獲取獨占鎖(針對獨占鎖)
* @param acquires 用於加鎖次數。一般傳入waitNode.arg(本代碼中就是1。為什么不用一個常量1,就不知道了?)
* @return
*/
public boolean tryLock(int acquires){
return commonMask.tryLock(acquires);
}
/**
* 嘗試解鎖(針對獨占鎖)
* @param releases 用於設定解鎖次數。一般傳入waitNode.arg
* @return
*/
public boolean tryUnlock(int releases){
return commonMask.tryUnlock(releases);
}
/**
* 獲取共享鎖(針對共享鎖)
*/
public void lockShared(){
commonMask.lockShared();
}
/**
* 解鎖(針對共享鎖)
*/
public boolean unLockShared(){
return commonMask.unLockShared();
}
/**
* 嘗試獲取共享鎖(針對共享鎖)
* @param acquires
* @return
*/
public boolean tryLockShared(int acquires){
return tryLockShared(acquires);
}
/**
* 嘗試解鎖(針對共享鎖)
* @param releases
* @return
*/
public boolean tryUnLockShared(int releases){
return commonMask.tryUnLockShared(releases);
}
}
這樣看來,順眼不少。但是,還是存在兩點問題。一方面,兩個Lock並沒有如實際源碼那樣,實現Lock接口與ReadWriteLock接口。另一方面,JarryReadWriteLock並沒有如實際源碼那樣,通過獲取對應Lock(如ReadLock與WriteLock),再進行對應鎖操作(其實,就是實現ReadWriteLock接口)。
那么就來進行改造吧。這里直接采用James大佬的最終版CommonMask-JameAQS了。 這里采用自己的AQS,因為自己的AQS有一些關鍵注解。
四,簡易JUC(版本四):
1.JarryAQS:
package tech.jarry.learning.netease.locks6;
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 JarryAQS {
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);
}
}
/**
* 獲取共享鎖(針對共享鎖)
*/
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 tryLock(int acquires){
throw new UnsupportedOperationException();
}
/**
* 嘗試解鎖(針對獨占鎖)
* @param releases 用於設定解鎖次數。一般傳入waitNode.arg
* @return
*/
public boolean tryUnlock(int releases){
throw new UnsupportedOperationException();
}
/**
* 嘗試獲取共享鎖(針對共享鎖)
* @param acquires
* @return
*/
public boolean tryLockShared(int acquires){
throw new UnsupportedOperationException();
}
/**
* 嘗試解鎖(針對共享鎖)
* @param releases
* @return
*/
public boolean tryUnLockShared(int releases){
throw new UnsupportedOperationException();
}
}
2.JarryReentrantLock:
package tech.jarry.learning.netease.locks6;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* @Description: 仿ReentrantLock,實現其基本功能及特性
* @Author: jarry
*/
public class JarryReentrantLock implements Lock {
private boolean isFair;
// 默認采用非公平鎖,保證效率(就是參照源碼)
public JarryReentrantLock() {
this.isFair = false;
}
public JarryReentrantLock(boolean isFair) {
this.isFair = isFair;
}
private JarryAQS jarryAQS = new JarryAQS(){
@Override
// 源碼中,則是將FairSync與NonFairSync作為兩個單獨內布類(extend Sync),來實現的。那樣會更加優雅,耦合度更低,擴展性更好(而且實際源碼,需要重寫的部分也會更多,而不像這個自定義demo,只有一個tryLock方法需要重寫)
public boolean tryLock(int acquires){
if (isFair){
return tryFairLock(acquires);
} else {
return tryNonFairLock(acquires);
}
}
private boolean tryFairLock(int acquires){
// 這里簡單注釋一下,如何實現公平鎖,其關鍵在於新的線程到來時,不再直接嘗試獲取鎖,而是直接塞入隊列(隊列為空,也是殊途同歸的)
// 1.判斷讀鎖(共享鎖)是否被占用
if (readCount.get() == 0){
// 2.判斷寫鎖(獨占鎖)是否被占用
int writeCountValue = writeCount.get();
if (writeCountValue == 0){
// 2.1 (核心區別)如果寫鎖未被占用,需要先對等待隊列waiters進行判斷
WaitNode head = waiters.peek();
if (head !=null && head.thread == Thread.currentThread()){
if (writeCount.compareAndSet(writeCountValue,writeCountValue+acquires)){
owner.set(Thread.currentThread());
return true;
} // 競爭失敗就直接返回false了
}
} else {
// 2.2 如果寫鎖已經被占用了,就判斷是否為當前線程持有,是否進行重入操作
if (owner.get() == Thread.currentThread()){
// 如果持有獨占鎖的線程就是當前線程,那么不需要改變owner,也不需要CAS,只需要修改writeCount的值即可
writeCount.set(writeCountValue + acquires);
return true;
}
}
}
// 以上操作失敗,就返回false,表示競爭鎖失敗
return false;
}
private boolean tryNonFairLock(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;
}
@Override
/**
*
先通過臨時變量c,判斷是否接下來的操作會完全解鎖。
如果完全解鎖,先釋放owner,再通過setState將count(源碼中為state)修改為0。
這樣調換了一下順序,但是避免了owner的原子性問題(畢竟別的線程是通過state來判斷是否可以競爭鎖,修改owner的)。
*/
public boolean tryUnlock(int releases) {
if (owner.get() != Thread.currentThread()){
throw new IllegalMonitorStateException();
}
int writeCountNextValue = writeCount.get() - releases;
boolean result = false;
if (writeCountNextValue == 0){
result = true;
owner.set(null);
}
writeCount.set(writeCountNextValue);
return result;
}
// 其它諸如共享鎖的相關操作,就不進行了。如果強行調用,只會發生UnsupportedOperationException
};
@Override
public void lock() {
jarryAQS.lock();
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return jarryAQS.tryLock(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void unlock() {
jarryAQS.unlock();
}
@Override
public Condition newCondition() {
return null;
}
}
3.JarryReadWriteLock:
package tech.jarry.learning.netease.locks6;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
/**
* @Description:
* @Author: jarry
*/
public class JarryReadWriteLock implements ReadWriteLock {
private JarryAQS jarryAQS = new JarryAQS(){
@Override
// 實際源碼,是通過Sync類,繼承AQS,再進行Override的。
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;
}
@Override
public boolean tryUnlock(int releases) {
if (owner.get() != Thread.currentThread()){
throw new IllegalMonitorStateException();
}
int writeCountNextValue = writeCount.get() - releases;
boolean result = false;
if (writeCountNextValue == 0){
result = true;
owner.set(null);
}
writeCount.set(writeCountNextValue);
return result;
}
@Override
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;
}
}
@Override
public boolean tryUnLockShared(int releases) {
while (true){
int readCountValue = readCount.get();
int readCountNext = readCountValue - releases;
if (readCount.compareAndSet(readCountValue,readCountNext)){
return readCountNext == 0;
}
}
}
};
/**
* 獲取獨占鎖(針對獨占鎖)
*/
public void lock(){
jarryAQS.lock();
}
/**
* 解鎖(針對獨占鎖)
*/
public void unlock(){
jarryAQS.unlock();
}
/**
* 嘗試獲取獨占鎖(針對獨占鎖)
* @param acquires 用於加鎖次數。一般傳入waitNode.arg(本代碼中就是1。為什么不用一個常量1,就不知道了?)
* @return
*/
public boolean tryLock(int acquires){
return jarryAQS.tryLock(acquires);
}
/**
* 嘗試解鎖(針對獨占鎖)
* @param releases 用於設定解鎖次數。一般傳入waitNode.arg
* @return
*/
public boolean tryUnlock(int releases){
return jarryAQS.tryUnlock(releases);
}
/**
* 獲取共享鎖(針對共享鎖)
*/
public void lockShared(){
jarryAQS.lockShared();
}
/**
* 解鎖(針對共享鎖)
*/
public boolean unLockShared(){
return jarryAQS.unLockShared();
}
/**
* 嘗試獲取共享鎖(針對共享鎖)
* @param acquires
* @return
*/
public boolean tryLockShared(int acquires){
return tryLockShared(acquires);
}
/**
* 嘗試解鎖(針對共享鎖)
* @param releases
* @return
*/
public boolean tryUnLockShared(int releases){
return jarryAQS.tryUnLockShared(releases);
}
@Override
public Lock readLock() {
return new Lock() {
@Override
public void lock() {
jarryAQS.lockShared();
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return jarryAQS.tryLockShared(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void unlock() {
jarryAQS.unLockShared();
}
@Override
public Condition newCondition() {
return null;
}
};
}
@Override
public Lock writeLock() {
return new Lock() {
@Override
public void lock() {
jarryAQS.lock();
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return jarryAQS.tryLock(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void unlock() {
jarryAQS.unlock();
}
@Override
public Condition newCondition() {
return null;
}
};
}
}
到了這里,其實JUC的核心-AQS,已經揭露出來了。通過這個,就可以把握住AQS核心運行機制。而實際的AQS,無非就是修改了存儲線程的WaitNodes,采用了Node形成鏈表。並通過head與tail的應用,來提高效率。當然還有lockInterruptibly等沒有提及,也有Condition這樣的大頭沒有說。這部分就留待以后有機會,再深入吧。
另外,再給出這方面的提升道路。如果希望更加深入理解AQS源碼,可以一邊閱讀源碼(思考源碼實現與自己實現的區別),一邊擴展自定義簡易AQS。
如,我了解到AQS是通過一個state來同時實現獨占鎖與共享鎖的持有數量。那么我就在JarryAQS中,去嘗試實現,從而進一步理解它。
五,簡易JUC(版本X-擴展state):
1.JarryAQS:
package tech.jarry.learning.netease.locks7;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
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 JarryAQS {
static final int SHARED_SHIFT = 16;
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/** Returns the number of shared holds represented in count */
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/** Returns the number of exclusive holds represented in count */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
/**
* The synchronization state.
*/
public volatile int state;
private static Unsafe unsafe;
private static long stateOffset;
static{
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
Field fieldi = JarryAQS.class.getDeclaredField("state");
stateOffset = unsafe.objectFieldOffset(fieldi);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
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);
}
}
/**
* 獲取共享鎖(針對共享鎖)
*/
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 tryLock(int acquires){
throw new UnsupportedOperationException();
}
/**
* 嘗試解鎖(針對獨占鎖)
* @param releases 用於設定解鎖次數。一般傳入waitNode.arg
* @return
*/
public boolean tryUnlock(int releases){
throw new UnsupportedOperationException();
}
/**
* 嘗試獲取共享鎖(針對共享鎖)
* @param acquires
* @return
*/
public boolean tryLockShared(int acquires){
throw new UnsupportedOperationException();
}
/**
* 嘗試解鎖(針對共享鎖)
* @param releases
* @return
*/
public boolean tryUnLockShared(int releases){
throw new UnsupportedOperationException();
}
}
2.JarryReentrantLock:
package tech.jarry.learning.netease.locks7;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* @Description: 仿ReentrantLock,實現其基本功能及特性
* @Author: jarry
*/
public class JarryReentrantLock implements Lock {
private boolean isFair;
// 默認采用非公平鎖,保證效率(就是參照源碼)
public JarryReentrantLock() {
this.isFair = false;
}
public JarryReentrantLock(boolean isFair) {
this.isFair = isFair;
}
// 實際源碼,是通過Sync類,繼承AQS,再進行Override的。
private JarryAQS jarryAQS = new JarryAQS(){
@Override
// 源碼中,則是將FairSync與NonFairSync作為兩個單獨內布類(extend Sync),來實現的。那樣會更加優雅,耦合度更低,擴展性更好(而且實際源碼,需要重寫的部分也會更多,而不像這個自定義demo,只有一個tryLock方法需要重寫)
public boolean tryLock(int acquires){
if (isFair){
return tryFairLock(acquires);
} else {
return tryNonFairLock(acquires);
}
}
private boolean tryFairLock(int acquires){
// 這里簡單注釋一下,如何實現公平鎖,其關鍵在於新的線程到來時,不再直接嘗試獲取鎖,而是直接塞入隊列(隊列為空,也是殊途同歸的)
// 1.判斷讀鎖(共享鎖)是否被占用
if (readCount.get() == 0){
// 2.判斷寫鎖(獨占鎖)是否被占用
int writeCountValue = writeCount.get();
if (writeCountValue == 0){
// 2.1 (核心區別)如果寫鎖未被占用,需要先對等待隊列waiters進行判斷
WaitNode head = waiters.peek();
if (head !=null && head.thread == Thread.currentThread()){
if (writeCount.compareAndSet(writeCountValue,writeCountValue+acquires)){
owner.set(Thread.currentThread());
return true;
} // 競爭失敗就直接返回false了
}
} else {
// 2.2 如果寫鎖已經被占用了,就判斷是否為當前線程持有,是否進行重入操作
if (owner.get() == Thread.currentThread()){
// 如果持有獨占鎖的線程就是當前線程,那么不需要改變owner,也不需要CAS,只需要修改writeCount的值即可
writeCount.set(writeCountValue + acquires);
return true;
}
}
}
// 以上操作失敗,就返回false,表示競爭鎖失敗
return false;
}
private boolean tryNonFairLock(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;
}
@Override
/**
*
先通過臨時變量c,判斷是否接下來的操作會完全解鎖。
如果完全解鎖,先釋放owner,再通過setState將count(源碼中為state)修改為0。
這樣調換了一下順序,但是避免了owner的原子性問題(畢竟別的線程是通過state來判斷是否可以競爭鎖,修改owner的)。
*/
public boolean tryUnlock(int releases) {
if (owner.get() != Thread.currentThread()){
throw new IllegalMonitorStateException();
}
int writeCountNextValue = writeCount.get() - releases;
boolean result = false;
if (writeCountNextValue == 0){
result = true;
owner.set(null);
}
writeCount.set(writeCountNextValue);
return result;
}
// 其它諸如共享鎖的相關操作,就不進行了。如果強行調用,只會發生UnsupportedOperationException
};
@Override
public void lock() {
jarryAQS.lock();
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return jarryAQS.tryLock(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void unlock() {
jarryAQS.unlock();
}
@Override
public Condition newCondition() {
return null;
}
}
3.JarryReadWriteLock:
package tech.jarry.learning.netease.locks7;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
/**
* @Description:
* @Author: jarry
*/
public class JarryReadWriteLock implements ReadWriteLock {
// 實際源碼,是通過Sync類,繼承AQS,再進行Override的。
private JarryAQS jarryAQS = new JarryAQS(){
@Override
public boolean tryLock(int acquires){
int stateTemp = state;
if (sharedCount(stateTemp) == 0){
int writeCountValue = exclusiveCount(stateTemp);
if (writeCountValue == 0){
if (compareAndSetState(stateTemp,stateTemp+acquires)){
owner.set(Thread.currentThread());
return true;
}
} else {
if (Thread.currentThread() == owner.get()){
compareAndSetState(stateTemp,stateTemp+acquires);
return true;
}
}
}
return false;
}
@Override
public boolean tryUnlock(int releases) {
int stateTemp = state;
if (owner.get() != Thread.currentThread()){
throw new IllegalMonitorStateException();
}
int writeCountNextValue = exclusiveCount(stateTemp) - releases;
boolean result = false;
if (writeCountNextValue == 0){
result = true;
owner.set(null);
}
compareAndSetState(stateTemp,stateTemp - releases);
return result;
}
@Override
public boolean tryLockShared(int acquires) {
while (true){
int stateTemp = state;
if (exclusiveCount(stateTemp) == 0 || owner.get() == Thread.currentThread()){
if (compareAndSetState(stateTemp, stateTemp+SHARED_UNIT*acquires)){
return true;
}
}
return false;
}
}
@Override
public boolean tryUnLockShared(int releases) {
while (true){
int stateTemp = state;
int readCountValue = sharedCount(stateTemp);
int readCountNext = readCountValue - releases;
if (compareAndSetState(stateTemp, stateTemp-SHARED_UNIT*readCountNext)){
return readCountNext == 0;
}
}
}
};
/**
* 獲取獨占鎖(針對獨占鎖)
*/
public void lock(){
jarryAQS.lock();
}
/**
* 解鎖(針對獨占鎖)
*/
public void unlock(){
jarryAQS.unlock();
}
/**
* 嘗試獲取獨占鎖(針對獨占鎖)
* @param acquires 用於加鎖次數。一般傳入waitNode.arg(本代碼中就是1。為什么不用一個常量1,就不知道了?)
* @return
*/
public boolean tryLock(int acquires){
return jarryAQS.tryLock(acquires);
}
/**
* 嘗試解鎖(針對獨占鎖)
* @param releases 用於設定解鎖次數。一般傳入waitNode.arg
* @return
*/
public boolean tryUnlock(int releases){
return jarryAQS.tryUnlock(releases);
}
/**
* 獲取共享鎖(針對共享鎖)
*/
public void lockShared(){
jarryAQS.lockShared();
}
/**
* 解鎖(針對共享鎖)
*/
public boolean unLockShared(){
return jarryAQS.unLockShared();
}
/**
* 嘗試獲取共享鎖(針對共享鎖)
* @param acquires
* @return
*/
public boolean tryLockShared(int acquires){
return tryLockShared(acquires);
}
/**
* 嘗試解鎖(針對共享鎖)
* @param releases
* @return
*/
public boolean tryUnLockShared(int releases){
return jarryAQS.tryUnLockShared(releases);
}
@Override
public Lock readLock() {
return new Lock() {
@Override
public void lock() {
jarryAQS.lockShared();
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return jarryAQS.tryLockShared(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void unlock() {
jarryAQS.unLockShared();
}
@Override
public Condition newCondition() {
return null;
}
};
}
@Override
public Lock writeLock() {
return new Lock() {
@Override
public void lock() {
jarryAQS.lock();
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public boolean tryLock() {
return jarryAQS.tryLock(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void unlock() {
jarryAQS.unlock();
}
@Override
public Condition newCondition() {
return null;
}
};
}
}
六,總結:
如果是從ReentrantLock實現,一步步走到這里,手動擼到這里,那么你對AQS的認知,就有了非常堅實的基礎。如果能夠在學習過程中,對照源碼學習(一邊自己實現,一邊了解源碼是怎么解決相關問題的),那么你對AQS的理解就很不錯了。即使有所欠缺,也只是AQS閱讀積累方面了。