java aqs详解_Java AQS底层原理解析
AQS底層原理
AQS(AbstractQueuedSynchronizer)是一個抽象同步隊列,JUC(java.util.concurrent)中很多同步鎖都是基于AQS實現的。
AQS的基本原理就是當一個線程請求共享資源的時候會判斷是否能夠成功操作這個共享資源,如果可以就會把這個共享資源設置為鎖定狀態,如果當前共享資源已經被鎖定了,那就把這個請求的線程阻塞住,也就是放到隊列中等待。
state變量:
AQS中有一個被volatile聲明的變量用來表示同步狀態
提供了getState()、setState()和compareAndSetState()方法來修改state狀態的值
// 返回同步狀態的當前值
protected final int getState() {
return state;
}
// 設置同步狀態的值
protected final void setState(int newState) {
state = newState;
}
// CAS操作修改state的值
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
對共享資源的操作方式:
上面說了AQS是JUC中很多同步鎖的底層實現,鎖也分很多種,有像ReentrantLock這樣的獨占鎖,也有ReentrantReadWriteLock這樣的共享鎖,所以AQS中也必然是包含這兩種操作方式的邏輯
獨占式
獲取資源的時候會調用acquire()方法,這里面會調用tryAcquire()方法去設置state變量,如果失敗的話就把當前線程放入一個Node中存入隊列
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
釋放資源的時候是調用realase()方法,會調用tryRelease()方法修改state變量,調用成果后會去喚醒隊列中Node里的線程,unparkSuccessor()方法就是判斷當前state變量是否符合喚醒的標準,如果合適就喚醒,否則繼續放回隊列
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
注意tryAcquire()和tryRelease()方法在AQS中都是空的,前面說了JUC中很多同步鎖都是基于AQS實現,所以加鎖和釋放鎖的邏輯都還不確定,因此是要在這些同步鎖中實現這兩個方法
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
共享式
獲取資源會調用acquireShared()方法,會調用tryAcquireShared()操作state變量,如果成功就獲取資源,失敗則放入隊列
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
釋放資源是調用releaseShared()方法,會調用tryReleaseShared()設置state變量,如果成功就喚醒隊列中的一個Node里的線程,不滿足喚醒條件則還放回隊列中
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
和獨占式一樣,tryAcquireShared()和tryReleaseShared()也是需要子類來提供
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
條件變量Condition
Condition中的signal()和await()方法類似與notify()和wait()方法,需要和AQS鎖配合使用。
public static void main(String[] args) throws InterruptedException {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
System.out.println(" t1 加鎖");
System.out.println("t1 start await");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 end await");
lock.unlock();
}
});
thread1.start();
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
System.out.println(" t2 加鎖");
System.out.println("t2 start signal");
condition.signal();
System.out.println("t2 end signal");
lock.unlock();
}
});
thread2.start();
}
在AQS中的原理
上面lock.newCondition()其實是new一個AQS中ConditionObject內部類的對象出來,這個對象里面有一個隊列,當調用await()方法的時候會存入一個Node節點到這個隊列中,并且調用park()方法阻塞當前線程,釋放當前線程的鎖。而調用singal()方法則會移除內部類中的隊列頭部的Node,然后放入AQS中的隊列中等待執行機會
同樣的,AQS并沒有實現newCondition()方法,也是需要子類自己去實現
總結:
本文內容大部分都是閱讀了<>這本書的內容,主要講了整個AQS的大致原理,和幾個最重要的方法,其實整個AQS的源碼是很復雜的,但是了解大致原理已經對我們熟悉運用那些JUC中的同步鎖有很大的幫助。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的java aqs详解_Java AQS底层原理解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 家境贫寒的情况下想组装一台电脑怎么办家境
- 下一篇: CAD崩溃了,怎么找回丢失的CAD图纸?