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

- lock():加鎖(不成功進(jìn)入阻塞隊(duì)列等待)
- lockInterruptibly():是否加鎖可打斷
- tryLock()://加鎖(不成功不會進(jìn)入阻塞隊(duì)列等待,可以去做其他事情)
- tryLock(long time,TimeUnit unit):加鎖(規(guī)定時間內(nèi)未獲得則放棄加鎖)
- unlock():釋放鎖
- newCondition():創(chuàng)建條件變量
二:創(chuàng)建一個內(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ù)表示失敗;0表示成功,但沒有剩余可用資源;正數(shù)表示成功,且有剩余資源。
- tryReleaseShared(int):共享方式。嘗試釋放資源,如果釋放后允許喚醒后續(xù)等待結(jié)點(diǎn)返回true,否則返回false。
三:我需要自定義一個獨(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 //嘗試加鎖 帶時間
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精品項(xiàng)目瑞吉外賣之新增菜品與分頁查詢篇
這篇文章主要為大家詳細(xì)介紹了java精品項(xiàng)目-瑞吉外賣訂餐系統(tǒng),此項(xiàng)目過大,分為多章獨(dú)立講解,本篇內(nèi)容為新增菜品和分頁查詢功能的實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-05-05
java實(shí)現(xiàn)二維碼生成的幾個方法(推薦)
本篇文章主要介紹了java實(shí)現(xiàn)二維碼生成的幾個方法(推薦),具有一定的參考價值,有興趣的可以了解一下。2016-12-12
Java并發(fā)Map面試線程安全數(shù)據(jù)結(jié)構(gòu)全面分析
本文將探討如何在Java中有效地應(yīng)對這些挑戰(zhàn),介紹一種強(qiáng)大的工具并發(fā)Map,它能夠幫助您管理多線程環(huán)境下的共享數(shù)據(jù),確保數(shù)據(jù)的一致性和高性能,深入了解Java中的并發(fā)Map實(shí)現(xiàn),包括ConcurrentHashMap和ConcurrentSkipListMap,及相關(guān)知識點(diǎn)2023-09-09
關(guān)于spring版本與JDK版本不兼容的問題及解決方法
這篇文章主要介紹了關(guān)于spring版本與JDK版本不兼容的問題,本文給大家?guī)砹私鉀Q方法,需要的朋友可以參考下2018-11-11
SpringBoot實(shí)現(xiàn)獲取客戶端IP地理位置
在當(dāng)今互聯(lián)的世界中,了解客戶端的地理位置對于提供個性化服務(wù)和增強(qiáng)用戶體驗(yàn)至關(guān)重要,使用本文為大家介紹了SpringBoot獲取客戶端IP地理位置的相關(guān)方法,需要的小伙伴可以參考下2023-11-11

