Java利用AQS實(shí)現(xiàn)自定義鎖
什么是AQS
AQS(AbstractQueuedSynchronizer),中文名抽象隊(duì)列同步器
AQS定義了一套多線程訪問共享資源的同步器框架,主要用來自定義鎖和同步器
AQS原理
AQS 核心思想:
- 如果被請求的共享資源空閑,則將當(dāng)前請求資源的線程設(shè)置為有效的工作線程,并且將共享資源設(shè)置為鎖定狀態(tài)。
- 如果被請求的共享資源被占用,將暫時(shí)獲取不到鎖的線程加入到阻塞隊(duì)列中,等待被喚醒和鎖的分配
實(shí)現(xiàn)核心思想的的隊(duì)列:CLH隊(duì)列
CLH隊(duì)列是一個(gè)虛擬的雙向隊(duì)列,AQS 是將每條請求共享資源的線程封裝成一個(gè) CLH 鎖隊(duì)列的一個(gè)結(jié)點(diǎn)(Node)來實(shí)現(xiàn)鎖的分配。

共享資源用 volatile 關(guān)鍵詞修飾,保證線程間的可見性
/**
* The synchronization state.
*/
private volatile int state;0狀態(tài)表示空閑,1狀態(tài)或以上表示不空閑
共享資源(state)的訪問方式有三種:
- getState() 獲得共享資源狀態(tài)
- setState() 設(shè)置共享資源狀態(tài)
- compareAndSetState() 更改共享資源狀態(tài)(底層unsafe類)
源代碼如下
/**
* Returns the current value of synchronization state.
* This operation has memory semantics of a {@code volatile} read.
* @return current state value
*/
protected final int getState() {
return state;
}
/**
* Sets the value of synchronization state.
* This operation has memory semantics of a {@code volatile} write.
* @param newState the new state value
*/
protected final void setState(int newState) {
state = newState;
}
/**
* Atomically sets synchronization state to the given updated
* value if the current state value equals the expected value.
* This operation has memory semantics of a {@code volatile} read
* and write.
*
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that the actual
* value was not equal to the expected value.
*/
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}利用AQS實(shí)現(xiàn)自定義鎖
一:首先創(chuàng)建一個(gè)類實(shí)現(xiàn)Lock接口,它有6個(gè)方法需要實(shí)現(xiàn)

- lock():加鎖(不成功進(jìn)入阻塞隊(duì)列等待)
- lockInterruptibly():是否加鎖可打斷
- tryLock()://加鎖(不成功不會進(jìn)入阻塞隊(duì)列等待,可以去做其他事情)
- tryLock(long time,TimeUnit unit):加鎖(規(guī)定時(shí)間內(nèi)未獲得則放棄加鎖)
- unlock():釋放鎖
- newCondition():創(chuàng)建條件變量
二:創(chuàng)建一個(gè)內(nèi)部類,繼承AbstractQueuedSynchronizer
可以根據(jù)需求重寫具體方法,總共有5種方法
- isHeldExclusively():該線程是否正在獨(dú)占資源。只有用到condition才需要去實(shí)現(xiàn)它。
- tryAcquire(int):獨(dú)占方式。嘗試獲取資源,成功則返回true,失敗則返回false。
- tryRelease(int):獨(dú)占方式。嘗試釋放資源,成功則返回true,失敗則返回false。
- tryAcquireShared(int):共享方式。嘗試獲取資源。負(fù)數(shù)表示失?。?表示成功,但沒有剩余可用資源;正數(shù)表示成功,且有剩余資源。
- tryReleaseShared(int):共享方式。嘗試釋放資源,如果釋放后允許喚醒后續(xù)等待結(jié)點(diǎn)返回true,否則返回false。
三:我需要自定義一個(gè)獨(dú)占鎖,不可重入,具有變量條件的鎖
分析
- 獨(dú)占鎖:AQS同步器中需要重寫?yīng)氄挤绞降墨@取資源tryAcquire(int)和釋放資源tryRelease(int)方法
- 不可重入:AQS同步器需要實(shí)現(xiàn)isHeldExclusively():
- 具有條件變量:AQS同步器中 return new ConditionObject();
具體代碼如下
//自定義鎖(不可重入)(獨(dú)占鎖)(條件變量)
class MyLock implements Lock{
//內(nèi)部類,AQS同步器類
class MySync extends AbstractQueuedSynchronizer{
@Override
protected boolean tryAcquire(int arg) {
if (compareAndSetState(0,1)){
System.out.println("獲得鎖成功");
//加上了鎖,并設(shè)置owner為當(dāng)前線程
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
System.out.println("獲得鎖失敗");
return false;
}
@Override
protected boolean tryRelease(int arg) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
public Condition newCondition(){
return new ConditionObject();
}
}
private MySync mySync = new MySync();
@Override //加鎖(不成功進(jìn)入阻塞隊(duì)列等待)
public void lock() {
mySync.acquire(1);
}
@Override //加鎖可打斷
public void lockInterruptibly() throws InterruptedException {
mySync.acquireInterruptibly(1);
}
@Override //加鎖(不成功不會進(jìn)入阻塞隊(duì)列等待,可以去做其他事情)
public boolean tryLock() {
return mySync.tryAcquire(1);
}
@Override //嘗試加鎖 帶時(shí)間
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return mySync.tryAcquireNanos(1,unit.toNanos(time));
}
@Override //釋放鎖
public void unlock() {
mySync.release(1);
}
@Override //創(chuàng)建條件變量
public Condition newCondition() {
return mySync.newCondition();
}
}到此這篇關(guān)于Java利用AQS實(shí)現(xiàn)自定義鎖的文章就介紹到這了,更多相關(guān)Java AQS實(shí)現(xiàn)自定義鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java Swing JList列表框的實(shí)現(xiàn)
這篇文章主要介紹了Java Swing JList列表框的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
IntelliJ IDEA編譯項(xiàng)目報(bào)錯(cuò) "xxx包不存在" 或 "找不到符號"
這篇文章主要介紹了IntelliJ IDEA編譯項(xiàng)目報(bào)錯(cuò) "xxx包不存在" 或 "找不到符號" ,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
java程序設(shè)計(jì)語言的優(yōu)勢及特點(diǎn)
在本篇文章里小編給大家分享的是一篇關(guān)于java程序設(shè)計(jì)語言的優(yōu)勢及特點(diǎn)的內(nèi)容,需要的朋友們可以學(xué)習(xí)參考下。2020-02-02
Java中本地緩存的4種實(shí)現(xiàn)方式總結(jié)
這篇文章主要介紹了Java中本地緩存的4種實(shí)現(xiàn)方式,分別是基礎(chǔ)緩存實(shí)現(xiàn)、GuavaLoadingCache、SpringBoot整合Caffeine和JetCache,通過實(shí)例代碼,詳細(xì)講解了每種緩存技術(shù)的特點(diǎn)和使用方法,需要的朋友可以參考下2025-04-04
Log4j按級別輸出日志到不同文件的實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄狶og4j按級別輸出日志到不同文件的實(shí)現(xiàn)方法。2016-11-11
springboot如何使用redis的incr創(chuàng)建分布式自增id
這篇文章主要介紹了springboot如何使用redis的incr創(chuàng)建分布式自增id,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
解決異常FileNotFoundException:class path resource找不到資源文件的問題
今天小編就為大家分享一篇關(guān)于解決異常FileNotFoundException:class path resource找不到資源文件的問題,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12

