Java的几个同步辅助类
Java為我們提供了一些同步輔助類,利用這些輔助類我們可以在多線程編程中,靈活地把握線程的狀態(tài)。
CountDownLatch
CountDownLatch一個(gè)同步輔助類,在完成一組正在其他線程中執(zhí)行的操作之前,它允許一個(gè)或多個(gè)線程一直等待。
再CountDownLatch中兩個(gè)比較關(guān)鍵的方法:
public void await() throws InterruptedException; public void countDown();CountDownLatch是一個(gè)計(jì)數(shù)器,它的構(gòu)造方法中需要設(shè)置一個(gè)數(shù)值,用來設(shè)定計(jì)數(shù)的次數(shù)。每次調(diào)用countDown()方法之后,這個(gè)計(jì)數(shù)器都會(huì)減去1,CountDownLatch會(huì)一直阻塞著調(diào)用await()方法的線程,直到計(jì)數(shù)器的值變?yōu)?。
設(shè)想有這樣一個(gè)功能需要Thread1、Thread2、Thread3、Thread4四條線程分別統(tǒng)計(jì)C、D、E、F四個(gè)盤的大小,所有線程都統(tǒng)計(jì)完畢交給主線程去做匯總,利用CountDownLatch來完成就非常輕松。
public class CountDownLatchTest {private static CountDownLatch count = new CountDownLatch(4);private static ExecutorService service = Executors.newFixedThreadPool(6);public static void main(String args[]) throws InterruptedException {for (int i = 0; i < 4; i++) {service.execute(() -> {// 模擬任務(wù)耗時(shí)try {int timer = new Random().nextInt(5);TimeUnit.SECONDS.sleep(timer);System.out.printf("%s時(shí)完成磁盤的統(tǒng)計(jì)任務(wù),耗費(fèi)%d秒.\n", new Date().toString(), timer);// 任務(wù)完成之后,計(jì)數(shù)器減一count.countDown();} catch (InterruptedException e) {e.printStackTrace();}});}// 主線程一直被阻塞,知道count的計(jì)數(shù)器被設(shè)置為0count.await();System.out.printf("%s時(shí)全部任務(wù)都完成,執(zhí)行合并計(jì)算.\n", new Date().toString());service.shutdown();} }CyclicBarrier
Barrier在英語中是屏障的意思,這個(gè)同步工具會(huì)阻塞調(diào)用的線程,直到條件滿足時(shí),阻塞的線程同時(shí)被打開。
public int await() throws InterruptedException, BrokenBarrierExceptionCyclicBarrier初始化的時(shí)候,設(shè)置一個(gè)屏障數(shù)。線程調(diào)用await()方法的時(shí)候,這個(gè)線程就會(huì)被阻塞,當(dāng)調(diào)用await()的線程數(shù)量到達(dá)屏障數(shù)的時(shí)候,主線程就會(huì)取消所有被阻塞線程的狀態(tài)。
在CyclicBarrier的構(gòu)造方法中,還可以設(shè)置一個(gè)barrierAction。
在所有的屏障都到達(dá)之后,會(huì)啟動(dòng)一個(gè)線程來運(yùn)行這里面的代碼。這里舉一個(gè)例子:百米賽跑的運(yùn)動(dòng)員起跑前需要準(zhǔn)備,所有選手準(zhǔn)備完畢之后,才可以同時(shí)起跑。
public class CyclicBarrierTest {private static CyclicBarrier cyclicBarrier = new CyclicBarrier(8);private static ExecutorService service = Executors.newFixedThreadPool(50);public static void main(String args[]) {for (int i = 1; i < 9; i++) {service.execute(new Thread(new Runner(i, cyclicBarrier)));}service.shutdown();} } // 運(yùn)動(dòng)員類 public class Runner implements Runnable {private int number;private CyclicBarrier cyclicBarrier;public Runner(int number, CyclicBarrier cyclicBarrier) {this.number = number;this.cyclicBarrier = cyclicBarrier;}@Overridepublic void run() {try {int timer = new Random().nextInt(5);TimeUnit.SECONDS.sleep(timer);System.out.printf("%d號(hào)選手準(zhǔn)備完畢,準(zhǔn)備時(shí)間%d\n", number, timer);cyclicBarrier.await();System.out.printf("%d號(hào)選手于%s時(shí)起跑!\n", number, new Date().toString());} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}} }輸出:
1號(hào)選手準(zhǔn)備完畢,準(zhǔn)備時(shí)間0 4號(hào)選手準(zhǔn)備完畢,準(zhǔn)備時(shí)間0 5號(hào)選手準(zhǔn)備完畢,準(zhǔn)備時(shí)間1 8號(hào)選手準(zhǔn)備完畢,準(zhǔn)備時(shí)間1 3號(hào)選手準(zhǔn)備完畢,準(zhǔn)備時(shí)間2 2號(hào)選手準(zhǔn)備完畢,準(zhǔn)備時(shí)間3 7號(hào)選手準(zhǔn)備完畢,準(zhǔn)備時(shí)間3 6號(hào)選手準(zhǔn)備完畢,準(zhǔn)備時(shí)間3 7號(hào)選手于Sun Mar 27 21:19:00 CST 2016時(shí)起跑! 2號(hào)選手于Sun Mar 27 21:19:00 CST 2016時(shí)起跑! 5號(hào)選手于Sun Mar 27 21:19:00 CST 2016時(shí)起跑! 6號(hào)選手于Sun Mar 27 21:19:00 CST 2016時(shí)起跑! 3號(hào)選手于Sun Mar 27 21:19:00 CST 2016時(shí)起跑! 8號(hào)選手于Sun Mar 27 21:19:00 CST 2016時(shí)起跑! 4號(hào)選手于Sun Mar 27 21:19:00 CST 2016時(shí)起跑! 1號(hào)選手于Sun Mar 27 21:19:00 CST 2016時(shí)起跑!相比CountDownLatch,CyclicBarrier是可以被循環(huán)使用的,而且遇到線程中斷等情況時(shí),還可以利用reset()方法,重置計(jì)數(shù)器,從這些方面來說,CyclicBarrier會(huì)比CountDownLatch更加靈活一些。
Semaphore
Semaphore被用于控制特定資源在同一個(gè)時(shí)間被訪問的個(gè)數(shù)。類似連接池的概念,保證資源可以被合理的使用。
Semaphore的幾個(gè)重要方法:
// 獲取資源 public void acquire() throws InterruptedException // 釋放資源 public void release()Semaphore的構(gòu)造方法可以設(shè)置一個(gè)int值來設(shè)置一個(gè)計(jì)數(shù)器,用于表示資源同時(shí)可以被多少外部環(huán)境使用。每使用一次acquire(),計(jì)數(shù)器都會(huì)去減去一,而每次調(diào)用release()計(jì)數(shù)器則會(huì)增加一。當(dāng)計(jì)數(shù)器的值為0的時(shí)候,外部的環(huán)境被阻塞,直到Semaphore有空閑的資源可以被使用。
public class SemaphoreTest {private static Semaphore semaphore = new Semaphore(3);private static ExecutorService service = Executors.newFixedThreadPool(6);public static void main(String args[]) {// 執(zhí)行9個(gè)任務(wù)for (int i = 0; i < 9; i++) {service.execute(() -> {try {semaphore.acquire();System.out.printf("%s時(shí)獲取資源,并調(diào)用.\n", new Date().toString());// 線程掛起3秒TimeUnit.SECONDS.sleep(3);semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}});}service.shutdown();} }運(yùn)行的結(jié)果就是:
Sun Mar 27 20:18:16 CST 2016時(shí)獲取資源,并調(diào)用. Sun Mar 27 20:18:16 CST 2016時(shí)獲取資源,并調(diào)用. Sun Mar 27 20:18:16 CST 2016時(shí)獲取資源,并調(diào)用. Sun Mar 27 20:18:19 CST 2016時(shí)獲取資源,并調(diào)用. Sun Mar 27 20:18:19 CST 2016時(shí)獲取資源,并調(diào)用. Sun Mar 27 20:18:19 CST 2016時(shí)獲取資源,并調(diào)用. Sun Mar 27 20:18:22 CST 2016時(shí)獲取資源,并調(diào)用. Sun Mar 27 20:18:22 CST 2016時(shí)獲取資源,并調(diào)用. Sun Mar 27 20:18:22 CST 2016時(shí)獲取資源,并調(diào)用.雖然線程池允許6個(gè)最大線程數(shù)量,但是同一個(gè)時(shí)間內(nèi)只用三個(gè)任務(wù)被執(zhí)行。
轉(zhuǎn)載于:https://www.cnblogs.com/whthomas/p/java_concurrent_tools.html
總結(jié)
以上是生活随笔為你收集整理的Java的几个同步辅助类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu安装atat
- 下一篇: Project:圆柱滚子轴承接触表面应力