同步器之CyclicBarrier

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环的 barrier。

CyclicBarrier 支持一个可选的 Runnable 命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此屏障操作 很有用。

 

在实际应用中,有时候需要多个线程同时工作以完成同一件事情,而且在完成过程中,往往会等待其他线程都完成某一阶段后再执行,等所有线程都到达某一个阶段后再统一执行。

比如有几个旅行团需要途经深圳、广州、韶关、长沙最后到达武汉。旅行团中有自驾游的,有徒步的,有乘坐旅游大巴的;这些旅行团同时出发,并且每到一个目的地,都要等待其他旅行团到达此地后再同时出发,直到都到达终点站武汉。

这时候CyclicBarrier就可以派上用场。CyclicBarrier最重要的属性就是参与者个数,另外最要方法是await()。当所有线程都调用了await()后,就表示这些线程都可以继续执行,否则就会等待。

 

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestCyclicBarrier {
    // 徒步需要的时间: Shenzhen, Guangzhou, Shaoguan, Changsha, Wuhan
    private static int[] timeWalk = { 5, 8, 15, 15, 10 };
    // 自驾游
    private static int[] timeSelf = { 1, 3, 4, 4, 5 };
    // 旅游大巴
    private static int[] timeBus = { 2, 4, 6, 6, 7 };

    static String now() {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        return sdf.format(new Date()) + ": ";
    }

    static class Tour implements Runnable {
        private int[] times;
        private CyclicBarrier barrier;
        private String tourName;

        public Tour(CyclicBarrier barrier, String tourName, int[] times) {
            this.times = times;
            this.tourName = tourName;
            this.barrier = barrier;
        }

        public void run() {
            try {
                Thread.sleep(times[0] * 1000);
                System.out.println(now() + tourName + " Reached Shenzhen");
                barrier.await();
                Thread.sleep(times[1] * 1000);
                System.out.println(now() + tourName + " Reached Guangzhou");
                barrier.await();
                Thread.sleep(times[2] * 1000);
                System.out.println(now() + tourName + " Reached Shaoguan");
                barrier.await();
                Thread.sleep(times[3] * 1000);
                System.out.println(now() + tourName + " Reached Changsha");
                barrier.await();
                Thread.sleep(times[4] * 1000);
                System.out.println(now() + tourName + " Reached Wuhan");
                barrier.await();
            } catch (InterruptedException e) {
            } catch (BrokenBarrierException e) {
            }
        }
    }

    public static void main(String[] args) {
         Runnable runner = new Runnable() {
             @Override
             public void run() {
                 System.out.println("我们都到了");
             }
         };
         // 三个旅行团
        CyclicBarrier barrier = new CyclicBarrier(3,runner);
        ExecutorService exec = Executors.newFixedThreadPool(3);
        exec.submit(new Tour(barrier, "WalkTour", timeWalk));
        exec.submit(new Tour(barrier, "SelfTour", timeSelf));
        exec.submit(new Tour(barrier, "BusTour", timeBus));
        exec.shutdown();
    }
}

运行结果:

14:30:49: SelfTour Reached Shenzhen
14:30:50: BusTour Reached Shenzhen
14:30:53: WalkTour Reached Shenzhen
我们都到了
14:30:56: SelfTour Reached Guangzhou
14:30:57: BusTour Reached Guangzhou
14:31:01: WalkTour Reached Guangzhou
我们都到了
14:31:05: SelfTour Reached Shaoguan
14:31:07: BusTour Reached Shaoguan
14:31:16: WalkTour Reached Shaoguan
我们都到了
14:31:20: SelfTour Reached Changsha
14:31:22: BusTour Reached Changsha
14:31:31: WalkTour Reached Changsha
我们都到了
14:31:36: SelfTour Reached Wuhan
14:31:38: BusTour Reached Wuhan
14:31:41: WalkTour Reached Wuhan
我们都到了

Barrier的主要作用就是让所有运行Tour的线程执行到有barrier.await();代码的地方等待,当所有的线程都到达这个地点时,就运行runner线程里的代码。

posted @ 2012-06-14 14:56  一筐  阅读(445)  评论(0编辑  收藏  举报