什么是AQS?
????????AQS(AbstractQueuedSynchronizer)是Java中用于實現鎖和同步器的基礎框架。它是一個抽象類,提供了一種靈活且強大的方式來實現各種同步器,如ReentrantLock、Semaphore、CountDownLatch等
AQS實現原理?
1、資源共享:AQS 中定義了一個整型的 state 變量來表示同步狀態,該狀態可以被多個線程共享,根據該狀態的不同值來表示不同的狀態(比如鎖被占用或者可用)。
- 等于0:表示當前同步狀態為空閑狀態,即沒有線程占用資源。
- 大于0:通常表示當前同步狀態被一個線程所占用,且在信號量的應用中也可以表示可用資源數量。
- 小于0:一般表示當前同步狀態已被某個線程占用,數值表示等待獲取資源的線程數量
2、模板方法:AQS 提供了 acquire() 和 release() 兩個模板方法,具體的同步器只需實現這兩個方法的邏輯即可。其中 acquire() 方法用于獲取資源,如果獲取不到則會將當前線程加入等待隊列;release() 方法用于釋放資源,并喚醒等待隊列中的其他線程。
3、等待隊列:AQS 使用一個雙向鏈表來維護等待線程的隊列,隊列中的線程按照先進先出的順序來獲取資源。當一個線程無法獲取資源時,會被加入到等待隊列中并進入等待狀態。
4、CAS 操作:AQS 使用 CAS(Compare And Swap)操作來對狀態進行原子性地修改,保證多線程并發操作時的數據一致性。
5、子類實現:具體的同步器(如 ReentrantLock、Semaphore 等)需要繼承 AQS,并根據自身需求實現 acquire() 和 release() 方法,來實現自定義的同步邏輯。
AQS的輔助類?
Condition
????????Condition(條件)是Java中用于線程之間通信的一種機制,常用于對線程的等待和喚醒操作。Condition通常與Lock一起使用,是Lock接口的一部分,用于替代傳統的Object的wait()和notify()/notifyAll()方法。在使用Condition時,首先需要獲得一個Lock對象,然后通過Lock對象的newCondition()方法創建一個Condition對象。線程可以通過Condition的await()方法進入等待狀態,當其他線程調用Condition的signal()或者signalAll()方法時,被等待的線程會被喚醒。使用Condition可以更加精細地控制線程的等待和喚醒,而不像使用Object的wait()和notify()/notifyAll()方法那樣具有局限性。
CountDownLatch(減少計數)
?CountDownLatch 是 Java 中的一個同步工具類,用于實現多個線程之間的同步,通過減少計數的方式實現線程之間的等待和通知。
- CountDownLatch 內部維護一個計數器,通過 countDown() 方法遞減計數,通過 await() 方法阻塞調用線程,直到計數器為 0。
- 在初始化 CountDownLatch 時需要指定計數器的初始值,每次調用 countDown() 方法都會使計數器減 1。
- 當計數器減至 0 時,所有在 await() 方法上阻塞的線程都會被喚醒,可以繼續執行后續操作。
舉例:風火雷電四大法王都能封印魔獸,但是隨著一個個法王的離開,每次調用countDown()方法,直至沒有一個法王存在,魔獸就會蘇醒。
CyclicBarrier(循環柵欄)
????????CyclicBarrier(循環柵欄)是Java中的一個同步輔助工具,用于在多個線程之間實現同步。它允許一組線程全部達到一個同步點后再繼續執行。當所有線程達到同步點時,CyclicBarrier會釋放它們并重置,以便可以被重復使用。
????????CyclicBarrier是通過指定一個計數值來初始化,當調用await()方法時,線程會等待直到所有參與者都調用了該方法,此時所有線程會被釋放并繼續執行。CyclicBarrier的一個常見應用場景是將問題分解成多個子任務并行處理,在每個子任務完成后使用CyclicBarrier來等待所有子任務完成后才繼續執行其他操作。
舉例:召集七顆龍珠即可召喚神龍,每當獲取一顆龍珠,會調用await()方法進行等待,一直集齊七顆,才能召喚神龍。
Semaphore(信號燈)
????????Semaphore(信號量)是一個用于控制對共享資源的訪問的同步工具。它通常用于限制同時訪問某個共享資源的線程數量,或者進行線程之間的同步。在Java中,Semaphore提供了一種計數信號量,可以用來控制同時訪問某個資源的線程數量,也可以用來實現生產者-消費者模式。
????????Semaphore內部維護著一個計數器,初始化時指定初始的許可數量,線程可以通過acquire()方法獲取許可(如果計數器大于0則獲取成功,計數器減1),通過release()方法釋放許可(計數器加1),當計數器為0時,acquire()方法會阻塞線程,直到有其他線程釋放許可。
舉例:六輛汽車三個停車位,通過acquire()方法占用停車位,通過release()方法離開停車位,但是只能同時停三輛車。
ps:以下是我整理的java面試資料,密碼是obht,感興趣的可以看看。最后,創作不易,覺得寫得不錯的可以點點關注!
鏈接:https://www.yuque.com/u39298356/uu4hxh?# 《Java面試寶典》?