一篇讀懂(空調aqs是什么意思啊)空調aqf什么意思,
1. AQS
1.1 AQS 簡單介紹
AQS 的全稱為(AbstractQueuedSynchronizer),這個類在 java.util.concurrent.locks 包下面。
AQS 是一個用來構建鎖和同步器的框架,使用 AQS 能簡單且高效地構造出應用廣泛的大量的同步器, 比如我們提到的 ReentrantLock,Semaphore,其他的諸如 ReentrantReadWriteLock,SynchronousQueue,FutureTask(jdk1.7) 等等皆是基于 AQS 的。當然,我們自己也能利用 AQS 非常輕松容易地構造出符合我們自己需求的同步器。
1.2 AQS 原理
1.2.1 AQS 原理概覽
AQS 核心思想是,如果被請求的共享資源空閑,則將當前請求資源的線程設置為有效的工作線程,并且將共享資源設置為鎖定狀態。如果被請求的共享資源被占用,那么就需要一套線程阻塞等待以及被喚醒 時鎖分配的機制,這個機制 AQS 是用 CLH 隊列鎖實現的,即將暫時獲取不到鎖的線程加入到隊列中。
看個 AQS (AbstractQueuedSynchronizer)原理圖:
AQS 使用一個 int 成員變量來表示同步狀態,通過內置的 FIFO 隊列來完成獲取資源線程的排隊工作。
AQS 使用 CAS 對該同步狀態進行原子操作實現對其值的修改。
狀態信息通過 protected 類型的getState , setState , compareAndSetState 進行操作
1.2.2 AQS 對資源的共享方式
AQS 定義兩種資源共享方式
1) Exclusive(獨占)
只有一個線程能執行,如 ReentrantLock。又可分為公平鎖和非公平鎖,ReentrantLock 同時支持兩種鎖,下面以 ReentrantLock 對這兩種鎖的定義做介紹:
下面來看 ReentrantLock 中相關的源代碼:
ReentrantLock 默認采用非公平鎖,因為考慮獲得更好的性能,通過 boolean 來決定是否用公平鎖(傳入 true 用公平鎖)。

ReentrantLock 中公平鎖的 lock 方法


非公平鎖的 lock 方法:


總結:公平鎖和非公平鎖只有兩處不同:

公平鎖和非公平鎖就這兩點區別,如果這兩次 CAS 都不成功,那么后面非公平鎖和公平鎖是一樣的, 都要進入到阻塞隊列等待喚醒。
相對來說,非公平鎖會有更好的性能,因為它的吞吐量比較大。當然,非公平鎖讓獲取鎖的時間變得更加不確定,可能會導致在阻塞隊列中的線程長期處于饑餓狀態。
1) Share(共享)

1.2.3 AQS 底層使用了模板方法模式

AQS 使用了模板方法模式,自定義同步器時需要重寫下面幾個 AQS 提供的模板方法:


1.3 Semaphore(信號量)-允許多個線程同時訪問
synchronized 和 ReentrantLock 都是一次只允許一個線程訪問某個資源,Semaphore(信號量)可以指定多個線程同時訪問某個資源。
示例代碼如下:


執行 acquire 方法阻塞,直到有一個許可證可以獲得然后拿走一個許可證;每個 rerelease方法增加一個許可證,這可能會釋放一個阻塞的 acquire 方法。然而,其實并沒有實際的許可證這個對象,Semaphore 只是維持了一個可獲得許可證的數量。 Semaphore 經常用于限制獲取某種資源的線程數量。
當然一次也可以一次拿取和釋放多個許可,不過一般沒有必要這樣做:

除了 acquire 方法之外,另一個比較常用的與之對應的方法是tryAcquire 方法,該方法如果獲取不到許可就立即返回 false。
Semaphore 有兩種模式,公平模式和非公平模式。
公平模式: 調用 acquire 的順序就是獲取許可證的順序,遵循 FIFO;
非公平模式: 搶占式的。
Semaphore 對應的兩個構造方法如下:

這兩個構造方法,都必須提供許可的數量,第二個構造方法可以指定是公平模式還是非公平模式,默認非公平模式。
補充:Semaphore與CountDownLatch一樣,也是共享鎖的一種實現。它默認構造AQS的state為permits。當執行任務的線程數量超出permits,那么多余的線程將會被放入阻塞隊列Park,并自旋判斷state是否大于0。只有當state大于0的時候,阻塞的線程才能繼續執行,此時先前執行任務的線程繼續執 行release方法,release方法使得state的變量會加1,那么自旋的線程便會判斷成功。如此,每次只有最多不超過permits數量的線程能自旋成功,便限制了執行任務線程的數量。
1.4 CountDownLatch (倒計時器)

1.4.1 CountDownLatch 的兩種典型用法

1.4.2 CountDownLatch 的使用示例


上面的代碼中,我們定義了請求的數量為 550,當這 550 個請求被處理完成之后,才會執行
System.out.println("finish");
與 CountDownLatch 的第一次交互是主線程等待其他線程。主線程必須在啟動其他線程后立即調用 CountDownLatch.await()方法。這樣主線程的操作就會在這個方法上阻塞,直到其他線程完成各自的任務。
其他 N 個線程必須引用閉鎖對象,因為他們需要通知CountDownLatch對象,他們已經完成了各自的任務。這種通知機制是通過CountDownLatch.countDown()方法來完成的;每調用一次這個方法,在構造函數中初始化的 count 值就減 1。所以當 N 個線程都調 用了這個方法,count 的值等于 0,然后主線程就能通過 await() 方法,恢復執行自己的任務。
再插一嘴: CountDownLatch 的await()方法使用不當很容易產生死鎖,比如我們上面代碼中的 for循環改為:
這樣就導致 count 的值沒辦法等于 0,然后就會導致一直等待。
1.4.3 CountDownLatch 的不足
CountDownLatch 是一次性的,計數器的值只能在構造方法中初始化一次,之后沒有任何機制再次對其設置值,當 CountDownLatch 使用完畢后,它不能再次被使用。
1.4.4 CountDownLatch 項常見面試題
解釋一下 CountDownLatch 概念?
CountDownLatch 和 CyclicBarrier 的不同之處?
給出一些 CountDownLatch 使用的例子?
CountDownLatch 類中主要的方法?
1.5 CyclicBarrier(循環柵欄)
CyclicBarrier 和 CountDownLatch 非常類似,它也可以實現線程間的技術等待,但是它的功能比CountDownLatch 更加復雜和強大。主要應用場景和 CountDownLatch 類似。
CountDownLatch的實現是基于AQS的,而CycliBarrier是基于 ReentrantLock(ReentrantLock也屬于AQS同步器)和 Condition 的.
CyclicBarrier 的字面意思是可循環使用(Cyclic)的屏障(Barrier)。它要做的事情是,讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最后一個線程到達屏障時,屏障才會開門,所有被屏障 攔截的線程才會繼續干活。CyclicBarrier 默認的構造方法是 CyclicBarrier(int parties) ,其參數表示屏障攔截的線程數量,每個線程調用await 方法告訴 CyclicBarrier 我已經到達了屏障,然后當前線程被阻塞。
再來看一下它的構造函數:
其中,parties 就代表了有攔截的線程的數量,當攔截的線程數量達到這個值的時候就打開柵欄,讓所有線程通過。
1.5.1 CyclicBarrier 的應用場景
1.5.2 CyclicBarrier 的使用示例
示例 1:
運行結果,如下:
可以看到當線程數量也就是請求數量達到我們定義的 5 個的時候, await 方法之后的方法才被執行。
另外,CyclicBarrier還提供一個更高級的構造函數CyclicBarrier(intparties,RunnablebarrierAction),用于在線程到達屏障時,優先執行barrierAction,方便處理更復雜的業務場景。示例代碼如下:
運行結果,如下:
1.5.3 CyclicBarrier 源碼分析
dowait(false, 0L) :
總結: CyclicBarrier 內部通過一個 count 變量作為計數器,cout 的初始值為 parties 屬性的初始化值,每當一個線程到了柵欄這里了,那么就將計數器減一。如果 count 值為 0 了,表示這是這一代最后一個線程到達柵欄,就嘗試執行我們構造方法中輸入的任務。
1.5.4CyclicBarrier 和 CountDownLatch 的區別
下面這個是國外一個大佬的回答:
CountDownLatch 是計數器,只能使用一次,而 CyclicBarrier 的計數器提供 reset 功能,可以多次使用。但是我不那么認為它們之間的區別僅僅就是這么簡單的一點。我們來從 jdk 作者設計的目的來看,javadoc 是這么描述它們的:
對于 CountDownLatch 來說,重點是“一個線程(多個線程)等待”,而其他的 N 個線程在完成“某件事情”之后,可以終止,也可以等待。而對于 CyclicBarrier,重點是多個線程,在任意一個線程沒有完成,所有的線程都必須等待。
CountDownLatch 是計數器,線程完成一個記錄一個,只不過計數不是遞增而是遞減,而
CyclicBarrier 更像是一個閥門,需要所有線程都到達,閥門才能打開,然后繼續執行。
1.6 ReentrantLock 和 ReentrantReadWriteLock
ReentrantLock 和 synchronized 的區別在上面已經講過了這里就不多做講解。另外,需要注意的是: 讀寫鎖 ReentrantReadWriteLock 可以保證多個線程可以同時讀,所以在讀操作遠大于寫操作的時候, 讀寫鎖就非常有用了。