JUC - 輔助類
JUC(java.util.concurrent)是在Java 5中引入的一個(gè)并發(fā)編程的擴(kuò)展庫,目的是為了更加方便、快捷和安全地實(shí)現(xiàn)并發(fā)編程。它提供了一系列的工具類、鎖、隊(duì)列以及原子類等來協(xié)調(diào)多線程之間的操作。
基于現(xiàn)代硬件不斷地發(fā)展,為了充分利用服務(wù)器資源,并發(fā)編程在我們的開發(fā)中已經(jīng)無處不在,今天主要了解下JUC包中提供的幾個(gè)工具類,讓我們?cè)诓l(fā)編程時(shí)提供助力。
簡(jiǎn)介
Java并發(fā)編程是一門復(fù)雜的技術(shù),其中有一些難點(diǎn)需要特別注意。以下是一些Java并發(fā)編程的難點(diǎn):
- 線程安全:多線程執(zhí)行的代碼必須是線程安全的,否則會(huì)產(chǎn)生競(jìng)態(tài)條件和其他問題。
- 死鎖:當(dāng)多個(gè)線程因?yàn)榛ハ嗟却渌€程釋放鎖而無法繼續(xù)執(zhí)行時(shí),就會(huì)產(chǎn)生死鎖。
- 競(jìng)態(tài)條件:當(dāng)多個(gè)線程試圖同時(shí)訪問同一個(gè)共享資源時(shí),就會(huì)產(chǎn)生競(jìng)態(tài)條件。
- 內(nèi)存可見性:多個(gè)線程同時(shí)訪問同一個(gè)變量時(shí),可能會(huì)產(chǎn)生內(nèi)存可見性問題,即一個(gè)線程對(duì)變量的修改不會(huì)立即被其他線程所感知。
- 并發(fā)集合類:Java提供了一些并發(fā)集合類,如ConcurrentHashMap和ConcurrentLinkedQueue,但使用它們需要注意一些細(xì)節(jié)問題。
- 線程池:線程池是Java并發(fā)編程中的一個(gè)重要概念,但線程池的使用也需要注意一些問題,如線程池大小、任務(wù)隊(duì)列類型等。
- CAS操作:Java提供了CAS(Compare-And-Swap)操作,可以用于實(shí)現(xiàn)非阻塞算法,但使用CAS操作需要非常小心,以免產(chǎn)生ABA問題等。
工具類
- CountDownLatch
CountDownLatch是一個(gè)同步輔助類,使用一個(gè)給定數(shù)量的計(jì)數(shù)器,當(dāng)該計(jì)數(shù)器不為0時(shí),將程序阻塞在wait()處,當(dāng)線程執(zhí)行完成后通過調(diào)用countDown()使計(jì)數(shù)器減一, 直到計(jì)數(shù)器為0后才會(huì)繼續(xù)執(zhí)行后續(xù)代碼。 主要實(shí)現(xiàn)某個(gè)任務(wù)依賴其他一個(gè)或多個(gè)異步任務(wù)的執(zhí)行結(jié)果的場(chǎng)景
核心方法:
/**
* 定義計(jì)數(shù)器數(shù)量,用于定義多少個(gè)執(zhí)行線程
*/
public CountDownLatch(int count);
/**
* 阻塞方法,直到計(jì)數(shù)器為0時(shí)才會(huì)繼續(xù)執(zhí)行后續(xù)代碼
*/
public void await();
/**
* 每次調(diào)用改方法,則計(jì)數(shù)器減一
*/
public void countDown();
- CyclicBarrier
CyclicBarrier內(nèi)部同樣定義了計(jì)數(shù)器,只不過每當(dāng)有線程執(zhí)行完后改計(jì)數(shù)器加一,直至達(dá)到定義數(shù)量后,執(zhí)行定義的回調(diào)函數(shù)與await()后續(xù)代碼。 與CountDownLatch相比,CyclicBarrier會(huì)對(duì)子任務(wù)阻塞,而CountDownLatch則阻塞主任務(wù);另外CyclicBarrier可以重復(fù)使用。 主要實(shí)現(xiàn)某個(gè)回調(diào)函數(shù)在一個(gè)或多個(gè)線程執(zhí)行完成后觸發(fā)的情形
核心方法:
/**
* 定義計(jì)數(shù)器數(shù)量與回調(diào)函數(shù)
*/
public CyclicBarrier(int parties, Runnable barrierAction);
/**
* 阻塞方法,當(dāng)有線程執(zhí)行到則計(jì)數(shù)器加一,等到達(dá)到目標(biāo)數(shù)后才會(huì)繼續(xù)后續(xù)代碼
*/
public int await();
/**
* 通過該方法可以實(shí)現(xiàn)計(jì)數(shù)器的重置
*/
public void reset();
- Semaphore
信號(hào)量通常用于限制可以訪問某些(物理或邏輯)資源的線程數(shù)。 適用于有限資源數(shù)量的控制
核心方法:
/**
* 定義許可數(shù)量
*/
public Semaphore(int permits);
/**
* 申請(qǐng)?jiān)S可,改方法會(huì)阻塞程序
*/
public void acquire();
/**
* 釋放許可
*/
public void release();
示例
CountDownLatch的使用場(chǎng)景
CountDownLatch是Java并發(fā)包中的一個(gè)工具類,它可以實(shí)現(xiàn)線程之間的協(xié)作。具體來說,CountDownLatch可以讓一個(gè)線程等待多個(gè)線程執(zhí)行完畢,再繼續(xù)執(zhí)行。CountDownLatch常用于以下場(chǎng)景:
- 主線程等待多個(gè)子線程執(zhí)行完畢。
- 多個(gè)子線程等待某個(gè)共同任務(wù)的完成。
- 模擬并發(fā)請(qǐng)求,等待所有請(qǐng)求都響應(yīng)完畢再進(jìn)行下一步操作。
- 統(tǒng)計(jì)多個(gè)線程執(zhí)行的時(shí)間。
@Test
public void test() throws InterruptedException {
int count = 10;
CountDownLatch countDownLatch = new CountDownLatch(count);
IntStream.range(0,count).forEach(i- >{
new Thread(()- >{
System.out.println( "執(zhí)行線程:"+ i );
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
countDownLatch.countDown();
}).start();
});
countDownLatch.await();
System.out.println("線程執(zhí)行完成");
}
CyclicBarrier的使用場(chǎng)景
它允許多個(gè)線程在某個(gè)屏障處等待,直到所有線程都到達(dá)該屏障時(shí)才會(huì)繼續(xù)執(zhí)行。
CyclicBarrier 適用于一組線程需要相互等待,直到所有線程都完成某個(gè)任務(wù)后才能繼續(xù)執(zhí)行下一步操作的場(chǎng)景。例如,一個(gè)大型的計(jì)算任務(wù)可以被分成多個(gè)子任務(wù), 每個(gè)子任務(wù)由一個(gè)線程執(zhí)行。當(dāng)所有子任務(wù)完成后,這些線程需要等待,直到所有子任務(wù)都完成,然后再執(zhí)行下一步操作。
另外,CyclicBarrier 還可以用于優(yōu)化代碼性能。例如,當(dāng)我們需要等待多個(gè)線程都完成某項(xiàng)工作后,才能進(jìn)行下一步操作。此時(shí),我們可以使用 CyclicBarrier 來實(shí)現(xiàn)等待, 而不是使用 Thread.sleep() 方法等待一段時(shí)間。這樣可以避免無謂的等待時(shí)間,提高代碼效率。
@Test
public void test() {
int count = 10;
AtomicBoolean finish = new AtomicBoolean(false);
CyclicBarrier cyclicBarrier = new CyclicBarrier(count, ()- >{
System.out.println("線程執(zhí)行完成");
finish.set(true);
});
IntStream.range(0,count).forEach(i- >{
new Thread(()- >{
System.out.println( "執(zhí)行線程:"+ i );
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (BrokenBarrierException e) {
throw new RuntimeException(e);
}
}).start();
});
while (!finish.get()){}
}
Semaphore的使用場(chǎng)景
它可以控制同時(shí)訪問某個(gè)共享資源的線程數(shù)量。常用于限制同時(shí)訪問某個(gè)資源的線程數(shù)量,例如數(shù)據(jù)庫連接池、線程池等。
- 控制并發(fā)線程數(shù):Semaphore可以限制并發(fā)線程數(shù),從而控制系統(tǒng)資源的使用情況。
- 控制訪問資源數(shù):Semaphore可以控制同時(shí)訪問某個(gè)資源的線程數(shù)量,例如數(shù)據(jù)庫連接池,限制連接數(shù)。
- 實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模型:Semaphore可以與阻塞隊(duì)列一起使用,實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模型,控制生產(chǎn)者和消費(fèi)者的數(shù)量。
- 多個(gè)線程間的協(xié)作:Semaphore可以用于多個(gè)線程之間的協(xié)作,例如某個(gè)線程需要等待某些條件滿足后才能繼續(xù)執(zhí)行,可以使用Semaphore來實(shí)現(xiàn)等待和喚醒操作。
@Test
public void test() {
int count = 10;
Semaphore semaphore = new Semaphore(3);
IntStream.range(0,count).forEach(i- >{
new Thread(()- >{
try {
semaphore.acquire();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println( "執(zhí)行線程:"+ i );
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
semaphore.release();
}).start();
});
while (true){}
}
結(jié)束語
涉及到線程的開發(fā)都伴隨著復(fù)雜性,不管是在代碼調(diào)試上還是理解線程切換與安全性上,JUC提供的各種強(qiáng)大的工具類將并發(fā)編程的復(fù)雜性進(jìn)行了封裝,不管是在使用或是擴(kuò)展上,都能通過簡(jiǎn)單的幾行代碼實(shí)現(xiàn)多線程的各種協(xié)調(diào)工作。
-
服務(wù)器
+關(guān)注
關(guān)注
12文章
9303瀏覽量
86061 -
JAVA
+關(guān)注
關(guān)注
19文章
2974瀏覽量
105138 -
多線程
+關(guān)注
關(guān)注
0文章
278瀏覽量
20071 -
工具
+關(guān)注
關(guān)注
4文章
314瀏覽量
27911
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論