1. 程式人生 > >Java併發程式設計中CountDownLatch和CyclicBarrier的使用

Java併發程式設計中CountDownLatch和CyclicBarrier的使用

在多執行緒程式設計中,經常會遇到一個執行緒等待一個或多個執行緒的場景,遇到這樣的場景應該如何解決?

如果是一個執行緒等待一個執行緒,則可以通過await()和notify()來實現;

如果是一個執行緒等待多個執行緒,則就可以使用CountDownLatch和CyclicBarrier來實現比較好的控制。

下面來詳細描述下CountDownLatch的應用場景:

例如:百米賽跑:8名運動員同時起跑,由於速度的快慢,肯定有會出現先到終點和晚到終點的情況,而終點有個統計成績的儀器,當所有選手到達終點時,它會統計所有人的成績並進行排序,然後把結果傳送到彙報成績的系統。

其實這就是一個CountDownLatch的應用場景:一個執行緒或多個執行緒等待其他執行緒執行達到某一目標後進行自己的下一步工作,而被等待的“其他執行緒”達到這個目標後繼續自己下面的任務。

這個場景中:

1. 被等待的“其他執行緒”------>8名運動員

2. 等待“其他執行緒”的這個執行緒------>終點統計成績的儀器

那麼,如何來通過CountDownLatch來實現上述場景的執行緒控制和排程呢?

jdk中CountDownLatch類有一個常用的構造方法:CountDownLatch(int count);

兩個常用的方法:await()和countdown()

其中count是一個計數器中的初始化數字,比如初始化的數字是2,當一個執行緒裡呼叫了countdown(),則這個計數器就減一,當執行緒呼叫了await(),則這個執行緒就等待這個計數器變為0,當這個計數器變為0時,這個執行緒繼續自己下面的工作。下面是上述CountDownLatch場景的實現:

Work類(運動員):

import java.util.concurrent.CountDownLatch;

public class Work implements Runnable {
 private int id;
 private CountDownLatch beginSignal;
 private CountDownLatch endSignal;
 
 public Work(int id, CountDownLatch begin, CountDownLatch end) {
  this.id = id;
  this.beginSignal = begin;
  this.endSignal = end;
 }

 @Override
 public void run() {
  try {
   beginSignal.await();
   System.out.println("起跑...");
   System.out.println("work" + id + "到達終點");
   endSignal.countDown();
   System.out.println("work" + id + "繼續幹其他事情");
  } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}

Main類(終點統計儀器):

import java.util.concurrent.CountDownLatch;

public class Main {
 
 public static void main(String[] args) {
  CountDownLatch begSignal = new CountDownLatch(1);
  CountDownLatch endSignal = new CountDownLatch(8);
  
  for (int i = 0; i < 8; i++) {
   new Thread(new Work(i, begSignal, endSignal)).start();
  }
  
  try {
   begSignal.countDown();  //統一起跑
   endSignal.await();      //等待運動員到達終點
   System.out.println("結果傳送到彙報成績的系統");
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }
}

下面詳細描述下CyclicBarrier的應用場景:

有四個遊戲玩家玩遊戲,遊戲有三個關卡,每個關卡必須要所有玩家都到達後才能允許通關。

其實這個場景裡的玩家中如果有玩家A先到了關卡1,他必須等待其他所有玩家都到達關卡1時才能通過,也就是說執行緒之間需要互相等待,這和CountDownLatch的應用場景有區別,CountDownLatch裡的執行緒是到了執行的目標後繼續幹自己的其他事情,而這裡的執行緒需要等待其他執行緒後才能繼續完成下面的工作。

jdk中CyclicBarrier類有兩個常用的構造方法:

1. CyclicBarrier(int parties)

這裡的parties也是一個計數器,例如,初始化時parties裡的計數是3,於是擁有該CyclicBarrier物件的執行緒當parties的計數為3時就喚醒,注:這裡parties裡的計數在執行時當呼叫CyclicBarrier:await()時,計數就加1,一直加到初始的值

2. CyclicBarrier(int parties, Runnable barrierAction)

這裡的parties與上一個構造方法的解釋是一樣的,這裡需要解釋的是第二個入參(Runnable barrierAction),這個引數是一個實現Runnable介面的類的物件,也就是說當parties加到初始值時就出發barrierAction的內容。

下面來實現上述的應用場景:

 Player類(玩家類)

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class Player implements Runnable {
 
 private CyclicBarrier cyclicBarrier;
 private int id;
 
 public Player(int id, CyclicBarrier cyclicBarrier) {
  this.cyclicBarrier = cyclicBarrier;
  this.id = id;
 }

 @Override
 public void run() {
  try {
   System.out.println("玩家" + id + "正在玩第一關...");
   cyclicBarrier.await();
   System.out.println("玩家" + id + "進入第二關...");
  } catch (InterruptedException e) {
   e.printStackTrace();
  } catch (BrokenBarrierException e) {
   e.printStackTrace();
  }
 }
}

GameBarrier類(關卡類,這裡控制玩家必須全部到達第一關結束的關口才能進入第二關)

import java.util.concurrent.CyclicBarrier;

public class GameBarrier {
 
 public static void main(String[] args) {
  CyclicBarrier cyclicBarrier = new CyclicBarrier(4, new Runnable() {
   
   @Override
   public void run() {
    System.out.println("所有玩家進入第二關!");
   }
  });
  
  for (int i = 0; i < 4; i++) {
   new Thread(new Player(i, cyclicBarrier)).start();
  }
 }
}

相關推薦

Java併發程式設計CountDownLatchCyclicBarrier的使用

在多執行緒程式設計中,經常會遇到一個執行緒等待一個或多個執行緒的場景,遇到這樣的場景應該如何解決? 如果是一個執行緒等待一個執行緒,則可以通過await()和notify()來實現; 如果是一個執行緒等待多個執行緒,則就可以使用CountDownLatch和Cycli

Java併發程式設計CountDownLatchCyclicBarrier Semaphore

在java 1.5中,提供了一些非常有用的輔助類來幫助我們進行併發程式設計,比如CountDownLatch,CyclicBarrier和Semaphore,今天我們就來學習一下這三個輔助類的用法。 以下是本文目錄大綱: 一.CountDownLatch用法 二.CyclicBarrier用法 三.S

14-Java併發程式設計CountDownLatchCyclicBarrierSemaphore

Java併發程式設計:CountDownLatch、CyclicBarrier和Semaphore   在java 1.5中,提供了一些非常有用的輔助類來幫助我們進行併發程式設計,比如CountDownLatch,CyclicBarrier和Semaphore,今天我們

Java併發程式設計CountDownLatchCyclicBarrierSemaphore

在java 1.5中,提供了一些非常有用的輔助類來幫助我們進行併發程式設計,比如CountDownLatch,CyclicBarrier和Semaphore,今天我們就來學習一下這三個輔助類的用法。 CountDownLatch   CountDownLa

Java併發程式設計CountDownLatchCyclicBarrierSemaphore

一.CountDownLatch用法   CountDownLatch類位於java.util.concurrent包下,利用它可以實現類似計數器的功能。比如有一個任務A,它要等待其他4個任務執行完畢之後才能執行,此時就可以利用CountDownLatch來實現

java併發學習03---CountDownLatch CyclicBarrier

CountDownLatch,顧名思義就是一個倒計時器。(其實Latch的意思是門閂,這個詞的本意是不斷的計數減一,減到0了就開啟門閂放行,但通常我們還是叫它倒計時器) 這個倒計時器和我們傳統意義上的倒計時器並不完全一樣,這個倒計時器的意思是,一開始規定幾個執行緒(比如說我們這裡一開始有10個執行緒),那麼

Java併發基礎:CountDownLatchCyclicBarrier

CountDownLatch概括 CountDownLatch能夠使一個執行緒在等待其他一個或多個執行緒執行結束之後,再繼續執行。 使用一個計數器進行實現。計數器初始值為執行緒的數量。當每一個執行緒完成自己任務後,計數器的值就會減一。當計數器的值為0時,表示所有的執行緒都

Java併發程式設計CountDownLatch & CyclicBarrier

文章目錄 CountDownLatch 概述 構造器 & 方法 構造器 方法 例子 程式碼 執行結果 CyclicBarrier

Java併發程式設計CountDownLatchCyclicBarrier實現一組執行緒相互等待、喚醒

java多執行緒應用場景不少,有時自己編寫程式碼又不太容易實現,好在concurrent包提供了不少實現類,還有google的guava包更是提供了一些最佳實踐,這讓我們在面對一些多執行緒的場景時,有了不少的選擇。這裡主要是看幾個涉及到多執行緒等待的工具類。一 CountDo

Java併發程式設計的設計模式解析(二)一個單例的七種寫法

Java單例模式是最常見的設計模式之一,廣泛應用於各種框架、中介軟體和應用開發中。單例模式實現起來比較簡單,基本是每個Java工程師都能信手拈來的,本文將結合多執行緒、類的載入等知識,系統地介紹一下單例模式的演變,並體現在7種不同的單例設計中。說到這個,非常像孔乙己裡那個“回字有四種寫法”的梗,不過與封建迂腐

Java併發程式設計volatile實現過程詳細解析

首先併發程式設計有三大特性: 可見性,有序性,原子性。volatile關鍵字實現了前面兩個特性。那麼它是如何實現這兩個特性的呢?   首先是可見性。可見性主要是讓快取,直接寫穿透到主存中。然後另外的cpu 通過底層的硬體層面的嗅探,可以發現自己cpu本地的快取已經失效。然後到主存中直接讀取。

16-Java併發程式設計:TimerTimerTask(轉載)

Java併發程式設計:Timer和TimerTask(轉載)   下面內容轉載自:   其實就Timer來講就是一個排程器,而TimerTask呢只是一個實現了run方法的一個類,而具體的TimerTask需要由你自己來實現,例如這樣: Timer timer =

java 併發包同步 CountDownLatchCyclicBarrier, Semaphore

java 執行緒併發包 通常為java.util.concurrent 下的包 執行緒包提供的同步結構主要有三個 CountDownLatch CyclicBarrier Semaphore C

多執行緒學習筆記六之併發工具類CountDownLatchCyclicBarrier

目錄 簡介 CountDownLatch 示例 實現分析 CountDownLatch與Thread.join() CyclicBarrier 實現分析 CountDownLatch和CyclicBarrier區別 簡介

Java併發程式設計的多執行緒是怎麼實現的?

眾所周知,在Java的知識體系中,併發程式設計是非常重要的一環,也是面試中必問的題,一個好的Java程式設計師是必須對併發程式設計這塊有所瞭解的。 併發必須知道的概念在深入學習併發程式設計之前,我們需要了解幾個基本的概念。同步和非同步同步和非同步用請求返回呼叫的方式來理解相對簡單。 同步:

Java併發程式設計:TimerTimerTask(轉載)

public Timer(boolean isDaemon) { this("Timer-" + serialNumber(), isDaemon); }    另外兩個構造方法負責傳入名稱和將timer啟動: public Timer(String name, boo

Java併發程式設計Semaphore的用法

Semaphore又稱訊號量,是作業系統中的一個概念,在Java併發程式設計中,訊號量控制的是執行緒併發的數量。 public Semaphore(int permits) 其中引數permits就是允許同時執行的執行緒數目; 下面先看一個訊號量實現單執行

關於Java併發程式設計的總結思考

  編寫優質的併發程式碼是一件難度極高的事情。Java語言從第一版本開始內建了對多執行緒的支援,這一點在當年是非常了不起的,但是當我們對併發程式設計有了更深刻的認識和更多的實踐後,實現併發程式設計就有了更多的方案和更好的選擇。本文是對併發程式設計的一點總結和思考,同時

Java併發程式設計Exchanger的用法

Exchanger類源於java.util.concurrent包,它可以在兩個執行緒之間傳輸資料,Exchanger中的public V exchange(V x)方法被呼叫後等待另一個執行緒到達交換

Java併發程式設計四種執行緒池及自定義執行緒使用教程

引言 通過前面的文章,我們學習了Executor框架中的核心類ThreadPoolExecutor ,對於執行緒池的核心排程機制有了一定的瞭解,並且成功使用ThreadPoolExecutor 建立了執行緒池。 而在Java中,除了ThreadPoolExecutor ,Executor框