日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java并发编程—线程同步类

發(fā)布時間:2024/4/15 java 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java并发编程—线程同步类 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文作者:洲洋1984

原文地址:Java 并發(fā)包中的高級同步工具

Java 中的并發(fā)包指的是 java.util.concurrent(簡稱 JUC)包和其子包下的類和接口,它為 Java 的并發(fā)提供了各種功能支持,比如:

  • 提供了線程池的創(chuàng)建類 ThreadPoolExecutor、Executors 等;
  • 提供了各種鎖,如 Lock、ReentrantLock 等;
  • 提供了各種線程安全的數(shù)據(jù)結(jié)構(gòu),如 ConcurrentHashMap、LinkedBlockingQueue、DelayQueue 等;
  • 提供了更加高級的線程同步結(jié)構(gòu),如 CountDownLatch、CyclicBarrier、Semaphore 、Phaser等。

在前面的章節(jié)中我們已經(jīng)詳細地介紹了線程池的使用、線程安全的數(shù)據(jù)結(jié)構(gòu)等,本文我們就重點學習一下 Java 并發(fā)包中更高級的線程同步類:CountDownLatch、CyclicBarrier、Semaphore 和 Phaser 等。

一、CountDownLatch 介紹和使用

CountDownLatch(閉鎖)可以看作一個只能做減法的計數(shù)器,可以讓一個或多個線程等待排隊執(zhí)行。CountDownLatch 有兩個重要的方法:

  • countDown():使計數(shù)器減 1;
  • await():當計數(shù)器不為 0 時,則調(diào)用該方法的線程阻塞,當計數(shù)器為 0 時,可以喚醒等待的一個或者全部線程。

CountDownLatch 使用場景:以生活中的情景為例,比如去醫(yī)院體檢,通常人們會提前去醫(yī)院排隊,但只有等到醫(yī)生開始上班,才能正式開始體檢,醫(yī)生也要給所有人體檢完才能下班,這種情況就要使用 CountDownLatch,流程為:患者排隊 → 醫(yī)生上班 → 體檢完成 → 醫(yī)生下班。

CountDownLatch 示例代碼如下:

// 醫(yī)院閉鎖 CountDownLatch hospitalLatch = new CountDownLatch(1); // 患者閉鎖 CountDownLatch patientLatch = new CountDownLatch(5); System.out.println("患者排隊"); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 5; i++) {final int j = i;executorService.execute(() -> {try {hospitalLatch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("體檢:" + j);patientLatch.countDown();}); } System.out.println("醫(yī)生上班"); hospitalLatch.countDown(); patientLatch.await(); System.out.println("醫(yī)生下班"); executorService.shutdown();

以上程序執(zhí)行結(jié)果如下:

患者排隊

醫(yī)生上班

體檢:4

體檢:0

體檢:1

體檢:3

體檢:2

醫(yī)生下班

二、CyclicBarrier 介紹和使用

CyclicBarrier(循環(huán)屏障),通過它可以實現(xiàn)讓一組線程等待滿足某個條件后同時執(zhí)行。CyclicBarrier 經(jīng)典使用場景是公交發(fā)車,為了簡化理解我們這里定義,每輛公交車只要上滿 4 個人就發(fā)車,后面來的人都會排隊依次遵循相應(yīng)的標準。

它的構(gòu)造方法為?CyclicBarrier(int parties,Runnable barrierAction)?其中,parties 表示有幾個線程來參與等待,barrierAction 表示滿足條件之后觸發(fā)的方法。CyclicBarrier 使用 await() 方法來標識當前線程已到達屏障點,然后被阻塞。

CyclicBarrier 示例代碼如下:

import java.util.concurrent.*; public class CyclicBarrierTest {public static void main(String[] args) throws InterruptedException {CyclicBarrier cyclicBarrier = new CyclicBarrier(4, new Runnable() {@Overridepublic void run() {System.out.println("發(fā)車了");}});for (int i = 0; i < 4; i++) {new Thread(new CyclicWorker(cyclicBarrier)).start();}}static class CyclicWorker implements Runnable {private CyclicBarrier cyclicBarrier;CyclicWorker(CyclicBarrier cyclicBarrier) {this.cyclicBarrier = cyclicBarrier;}@Overridepublic void run() {for (int i = 0; i < 2; i++) {System.out.println("乘客:" + i);try {cyclicBarrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}}} }

以上程序執(zhí)行結(jié)果如下:

乘客:0

乘客:0

乘客:0

乘客:0

發(fā)車了

乘客:1

乘客:1

乘客:1

乘客:1

發(fā)車了

三、Semaphore 介紹和使用

Semaphore(信號量)用于管理多線程中控制資源的訪問與使用。Semaphore 就好比停車場的門衛(wèi),可以控制車位的使用資源。比如來了 5 輛車,只有 2 個車位,門衛(wèi)可以先放兩輛車進去,等有車出來之后,再讓后面的車進入。

Semaphore 示例代碼如下:

Semaphore semaphore = new Semaphore(2); ThreadPoolExecutor semaphoreThread = new ThreadPoolExecutor(10, 50, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); for (int i = 0; i < 5; i++) {semaphoreThread.execute(() -> {try {// 堵塞獲取許可semaphore.acquire();System.out.println("Thread:" + Thread.currentThread().getName() + " 時間:" + LocalDateTime.now());TimeUnit.SECONDS.sleep(2);// 釋放許可semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}); }

以上程序執(zhí)行結(jié)果如下:

Thread:pool-1-thread-1 時間:2019-07-10 21:18:42

Thread:pool-1-thread-2 時間:2019-07-10 21:18:42

Thread:pool-1-thread-3 時間:2019-07-10 21:18:44

Thread:pool-1-thread-4 時間:2019-07-10 21:18:44

Thread:pool-1-thread-5 時間:2019-07-10 21:18:46

四、Phaser(移相器)

是 JDK 7 提供的,它的功能是等待所有線程到達之后,才繼續(xù)或者開始進行新的一組任務(wù)。比如有一個旅行團,我們規(guī)定所有成員必須都到達指定地點之后,才能發(fā)車去往景點一,到達景點之后可以各自游玩,之后必須全部到達指定地點之后,才能繼續(xù)發(fā)車去往下一個景點,類似這種場景就非常適合使用 Phaser。

Phaser 示例代碼如下:

public class Lesson5\_6 {public static void main(String[] args) throws InterruptedException {Phaser phaser = new MyPhaser();PhaserWorker[] phaserWorkers = new PhaserWorker[5];for (int i = 0; i < phaserWorkers.length; i++) {phaserWorkers[i] = new PhaserWorker(phaser);// 注冊 Phaser 等待的線程數(shù),執(zhí)行一次等待線程數(shù) +1phaser.register();}for (int i = 0; i < phaserWorkers.length; i++) {// 執(zhí)行任務(wù)new Thread(new PhaserWorker(phaser)).start();}}static class PhaserWorker implements Runnable {private final Phaser phaser;public PhaserWorker(Phaser phaser) {this.phaser = phaser;}@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " | 到達" );phaser.arriveAndAwaitAdvance(); // 集合完畢發(fā)車try {Thread.sleep(new Random().nextInt(5) * 1000);System.out.println(Thread.currentThread().getName() + " | 到達" );phaser.arriveAndAwaitAdvance(); // 景點 1 集合完畢發(fā)車Thread.sleep(new Random().nextInt(5) * 1000);System.out.println(Thread.currentThread().getName() + " | 到達" );phaser.arriveAndAwaitAdvance(); // 景點 2 集合完畢發(fā)車} catch (InterruptedException e) {e.printStackTrace();}}}// Phaser 每個階段完成之后的事件通知static class MyPhaser extends Phaser{@Overrideprotected boolean onAdvance(int phase, int registeredParties) { // 每個階段執(zhí)行完之后的回調(diào)switch (phase) {case 0:System.out.println("==== 集合完畢發(fā)車 ====");return false;case 1:System.out.println("==== 景點1集合完畢,發(fā)車去下一個景點 ====");return false;case 2:System.out.println("==== 景點2集合完畢,發(fā)車回家 ====");return false;default:return true;}}} }

以上程序執(zhí)行結(jié)果如下:

Thread-0 | 到達

Thread-4 | 到達

Thread-3 | 到達

Thread-1 | 到達

Thread-2 | 到達

==== 集合完畢發(fā)車 ====

Thread-0 | 到達

Thread-4 | 到達

Thread-1 | 到達

Thread-3 | 到達

Thread-2 | 到達

==== 景點1集合完畢,發(fā)車去下一個景點 ====

Thread-4 | 到達

Thread-3 | 到達

Thread-2 | 到達

Thread-1 | 到達

Thread-0 | 到達

==== 景點2集合完畢,發(fā)車回家 ====

相關(guān)面試題

1.以下哪個類用于控制某組資源的訪問權(quán)限?

  • A:Phaser
  • B:Semaphore
  • C:CountDownLatch
  • D:CyclicBarrier

答:B

2.以下哪個類不能被重用?

  • A:Phaser
  • B:Semaphore
  • C:CountDownLatch
  • D:CyclicBarrier

答:C

3.以下哪個方法不屬于 CountDownLatch 類?

  • A:await()
  • B:countDown()
  • C:getCount()
  • D:release()

答:D。release() 是 Semaphore 的釋放許可的方法,CountDownLatch 類并不包含此方法。

4.CyclicBarrier 與 CountDownLatch 有什么區(qū)別?

答:CyclicBarrier 與 CountDownLatch 本質(zhì)上都是依賴 volatile 和 CAS 實現(xiàn)的,它們區(qū)別如下:

  • CountDownLatch 只能使用一次,而 CyclicBarrier 可以使用多次。
  • CountDownLatch 是手動指定等待一個或多個線程執(zhí)行完成再執(zhí)行,而 CyclicBarrier 是 n 個線程相互等待,任何一個線程完成之前,所有的線程都必須等待。

5.以下哪個類不包含 await() 方法?

  • A:Semaphore
  • B:CountDownLatch
  • C:CyclicBarrier

答:A

6.以下程序執(zhí)行花費了多長時間?

Semaphore semaphore = new Semaphore(2); ThreadPoolExecutor semaphoreThread = new ThreadPoolExecutor(10, 50, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); for (int i = 0; i < 3; i++) {semaphoreThread.execute(() -> {try {semaphore.release();System.out.println("Hello");TimeUnit.SECONDS.sleep(2);semaphore.acquire();} catch (InterruptedException e) {e.printStackTrace();}}); }
  • A:1s 以內(nèi)
  • B:2s 以上

答:A。循環(huán)先執(zhí)行了 release() 也就是釋放許可的方法,因此程序可以一次性執(zhí)行 3 個線程,同時會在 1s 以內(nèi)執(zhí)行完。

7.Semaphore 有哪些常用的方法?

答:常用方法如下:

  • acquire():獲取一個許可。
  • release():釋放一個許可。
  • availablePermits():當前可用的許可數(shù)。
  • acquire(int n):獲取并使用 n 個許可。
  • release(int n):釋放 n 個許可。

8.Phaser 常用方法有哪些?

答:常用方法如下:

  • register():注冊新的參與者到 Phaser
  • arriveAndAwaitAdvance():等待其他線程執(zhí)行
  • arriveAndDeregister():注銷此線程
  • forceTermination():強制 Phaser 進入終止態(tài)
  • isTerminated():判斷 Phaser 是否終止

9.以下程序是否可以正常執(zhí)行?“發(fā)車了”打印了多少次?

import java.util.concurrent.*; public class TestMain {public static void main(String[] args) {CyclicBarrier cyclicBarrier = new CyclicBarrier(4, new Runnable() {@Overridepublic void run() {System.out.println("發(fā)車了");}});for (int i = 0; i < 4; i++) {new Thread(new CyclicWorker(cyclicBarrier)).start();}}static class CyclicWorker implements Runnable {private CyclicBarrier cyclicBarrier;CyclicWorker(CyclicBarrier cyclicBarrier) {this.cyclicBarrier = cyclicBarrier;}@Overridepublic void run() {for (int i = 0; i < 2; i++) {System.out.println("乘客:" + i);try {cyclicBarrier.await();System.out.println("乘客 II:" + i);cyclicBarrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}}} }

答:可以正常執(zhí)行,因為執(zhí)行了兩次 await(),所以“發(fā)車了”打印了 4 次。

總結(jié)

本文我們介紹了四種比 synchronized 更高級的線程同步類,其中 CountDownLatch、CyclicBarrier、Phaser 功能比較類似都是實現(xiàn)線程間的等待,只是它們的側(cè)重點有所不同,其中 CountDownLatch 一般用于等待一個或多個線程執(zhí)行完,才執(zhí)行當前線程,并且 CountDownLatch 不能重復使用;CyclicBarrier 用于等待一組線程資源都進入屏障點再共同執(zhí)行;Phaser 是 JDK 7 提供的功能更加強大和更加靈活的線程輔助工具,等待所有線程達到之后,繼續(xù)或開始新的一組任務(wù),Phaser 提供了動態(tài)增加和消除線程同步個數(shù)功能。而 Semaphore 提供的功能更像鎖,用于控制一組資源的訪問權(quán)限。

總結(jié)

以上是生活随笔為你收集整理的Java并发编程—线程同步类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。