CyclicBarrier的構造函數爲CyclicBarrier(int parties,Runnable barrierAction):在CyclicBarrier初始化的時候指定參與者的數量,並且支持一個可選的Runnable命令,在一組線程中的最後一個線程到達之後(但在釋放所有線程之前),該命令只在每個屏障點運行一次,並且由最後一個到達屏障的線程執行該屏障點的任務。若在繼續所有參與線程之前更新共享狀態,此屏障操作很有用。參與者調用awart法進入阻塞狀態直到參與者的個數達到指定數量,此時最後一個到達的線程執行預定的屏障任務,然後釋放所有的線程。需要注意的是,除了常見的InterruptedException以外,CyclicBarrier 的 await 的方法還會拋出 BrokenBarrierException,這個異常通常發生在CyclicBarrier被重置或者別的阻塞在CyclicBarrier.await()上的線程被打斷。同時,CyclicBarrier的await方法帶有返回值,可以得到到達屏障處的線程的索引,通俗一點說就是後面還有幾個線程沒有執行await。注:這裏parties裏的計數在運行時當調用await()時,計數就加1,一直加到初始的值。
下面舉例說明該類的用法:我們編寫一個用於計算ln(1-x)的程序。其中ln爲自然對數。計算方式爲:ln(1-x)=-(x + x2/2 + x3/3 + x4/4 + x5/5 + ...) where |x| < 1 。我們將創建線程來計算這個級數的每一項。這裏只計算10項,所以需要創建10個線程,每個線程將計算結果放入公共數組中,並且在屏障中等待其他線程,當每個線程完成後,最後一個到達的線程完成最後一項的計算並求得總和並顯示給用戶。
源碼如下:
- import java.util.concurrent.BrokenBarrierException;
- import java.util.concurrent.CyclicBarrier;
- public class NaturalLogCalc {
- private static final int numberOfitems = 10;// 計算前十個即可,所以需要十個線程來完成
- // 給個線程將計算結果都放在數組中
- private static double[] termArray = new double[numberOfitems];
- private static final float x = 0.2f;// 計算x的ln值
- public static void main(String[] args) {
- CyclicBarrier barrier = new CyclicBarrier(numberOfitems,
- // 屏障打破後該Runnable就可以執行了,在本例中就是當所有線程將每個項目計算完
- // 成之後屏障就被打破,從而計算每個值之和,即爲所求結果
- new Runnable() {
- @Override
- public void run() {
- System.out.println("Computing series sum");
- double sum = 0;
- // 第一項爲0.2f,但是經過Math.pow之後就變成了:0.20000000298023224
- for (double term : termArray) {
- sum += term;
- }
- System.out.println("ln(1-" + x + ") equals " + -sum);
- System.out.println(Thread.currentThread().getName());
- }
- });
- for (int i = 0; i < numberOfitems; i++) {
- new Thread(new NaturalLogCalc().new TermCalc(barrier, i), "Thread-"
- + (i + 1)).start();
- }
- System.out.println("Waiting...");
- }
- // 每一個線程執行各自對應的項目,並放入數組中,便於計算總和
- // ln(1-x)=-(x + x2/2 + x3/3 + x4/4 + x5/5 + ...) where |x| < 1
- private class TermCalc implements Runnable {
- private int termIndex;
- private CyclicBarrier barrier;
- public TermCalc(CyclicBarrier barrier, int termIndex) {
- this.barrier = barrier;
- this.termIndex = termIndex;
- }
- @Override
- public void run() {
- double result = Math.pow(x, termIndex + 1) / (termIndex + 1);
- termArray[termIndex] = result;
- System.out.println("Term " + (termIndex + 1) + ":" + result);
- try {
- barrier.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (BrokenBarrierException e) {
- e.printStackTrace();
- }
- }
- }
- }
- Waiting...
- Term 1:0.20000000298023224 //第一項爲原始值float類型,計算之後爲double,精度變大,所以不再是0.02,而是這個值。
- Term 10:1.0240001525879009E-8
- Term 6:1.0666667620341019E-5
- Term 9:5.688889651828388E-8
- Term 7:1.8285716193063003E-6
- Term 5:6.400000476837173E-5
- Term 2:0.020000000596046452
- Term 8:3.2000003814697465E-7
- Term 4:4.0000002384185847E-4
- <span style="color:#ff0000;">Term 3</span>:0.002666666785875958
- Computing series sum
- ln(1-0.2) equals -0.22314355275894068
- Thread-3//最後一個到達屏障的線程執行總和</span>