1. 程式人生 > >執行緒同步工具CyclicBarrier的使用

執行緒同步工具CyclicBarrier的使用

  上一節中總結了Semaphore同步工具的使用,Semaphore主要提供了一個記數訊號量,允許最大執行緒數執行。CyclicBarrier是另一個同步工具,這一節主要來總結一下CyclicBarrier的使用。先看一下官方的對CyclicBarrier的介紹:

一個同步輔助類,它允許一組執行緒互相等待,直到到達某個公共屏障點 (common barrier point)。在涉及一組固定大小的執行緒的程式中,這些執行緒必須不時地互相等待,此時 CyclicBarrier 很有用。因為該 barrier 在釋放等待執行緒後可以重用,所以稱它為迴圈 的 barrier。

  我的解釋是這樣的:

CyclicBarrier 可以使不同的執行緒彼此等待,在不同的執行緒都執行完了後,再執行下面的程式。比如A、B、C三個同學要去玩,大巴在校門口,A、B、C分別從各自的寢室出來,先後到達大巴處,先來的必須等待,直到三個同學都來了,大巴才能走。他們要玩兩個地方M和N,到了M處,三個同學又各自去玩了,玩完後各自回到大巴上,先回來的必須等待,直到三個同學都到了,大巴才能到N處,這個大巴可以迴圈利用。這個大巴就是CyclicBarrier。

  CyclicBarrier 同步工具相對來說比較簡單,因為功能很明確,下面寫一個CyclicBarrier 的示例程式碼:

public class
CyclicBarrierTest {
public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); final CyclicBarrier cb = new CyclicBarrier(3); //設定要三個執行緒等待,都執行完了再往下執行 System.out.println("初始化:當前有" + (cb.getNumberWaiting() + "個執行緒在等待")); //3個任務
for (int i = 0; i < 3; i++) { Runnable run = new Runnable() { public void run() { try { Thread.sleep((long)(Math.random()*10000)); System.out.println(Thread.currentThread().getName() + "即將到達集合點1,當前已有" + (cb.getNumberWaiting()+1) + "個執行緒到達," + (cb.getNumberWaiting()==2?"都到齊了,去集合點2!":"正在等候……")); // 訪問完後,釋放 ,如果遮蔽下面的語句,則在控制檯只能列印3條記錄,之後執行緒一直阻塞 cb.await(); //等待 Thread.sleep((long)(Math.random()*10000)); System.out.println(Thread.currentThread().getName() + "即將到達集合點2,當前已有" + (cb.getNumberWaiting()+1) + "個執行緒到達," + (cb.getNumberWaiting()==2?"都到齊了,去集合點3!":"正在等候……")); cb.await(); Thread.sleep((long)(Math.random()*10000)); System.out.println(Thread.currentThread().getName() + "即將到達集合點3,當前已有" + (cb.getNumberWaiting()+1) + "個執行緒到達," + (cb.getNumberWaiting()==2?"都到齊了,執行完畢!":"正在等候……")); cb.await(); } catch (Exception e) { } } }; service.execute(run); //執行任務 } service.shutdown(); //關閉執行緒 } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

  從程式碼中可以看出,CyclicBarrier 的使用主要有兩點,一是初始化,二是呼叫await()方法。這個await()方法也就是官方解釋中的“公共屏障點”,到了這個點,所有執行緒都得等待,直到規定數量的執行緒全部到達才能往下執行。看一下執行效果:

初始化:當前有0個執行緒在等待 pool-1-thread-3即將到達集合點1,當前已有1個執行緒到達,正在等候…… pool-1-thread-2即將到達集合點1,當前已有2個執行緒到達,正在等候…… pool-1-thread-1即將到達集合點1,當前已有3個執行緒到達,都到齊了,去集合點2! pool-1-thread-2即將到達集合點2,當前已有1個執行緒到達,正在等候…… pool-1-thread-3即將到達集合點2,當前已有2個執行緒到達,正在等候…… pool-1-thread-1即將到達集合點2,當前已有3個執行緒到達,都到齊了,去集合點3! pool-1-thread-3即將到達集合點3,當前已有1個執行緒到達,正在等候…… pool-1-thread-1即將到達集合點3,當前已有2個執行緒到達,正在等候…… pool-1-thread-2即將到達集合點3,當前已有3個執行緒到達,都到齊了,執行完畢!

  CyclicBarrier 的應用場合也很明顯:在某種需求中,比如一個大型的任務,常常需要分配好多子任務去執行,只有當所有子任務都執行完成時候,才能執行主任務,這時候,就可以選擇CyclicBarrier了。   可以再確切一點:假如我們需要統計全國的業務資料,其中各省的資料庫是獨立的,也就是說按省分庫。並且統計的資料量很大,統計過程也比較慢。為了提高效能,快速計算。我們採取併發的方式,多個執行緒同時計算各省資料,最後再彙總統計,在這裡CyclicBarrier就非常有用。   關於CyclicBarrier 同步工具就總結這麼多吧!