CountDownLatch和CyclicBarrier用法及例子

CountDownLatch和CyclicBarrier用法及例子

1.都是用来实现其他任务都完成后,然后再执行一个任务的需求,类似赛跑比赛,需要等所有运动员到达终点后,才能开始下一步颁奖。
2.CountDownLatch是一次性的,不能重复使用;CyclicBarrier是可重复的;
3.CountDownLatch使用时,在每个需要等待的地方调用await,在每个触发条件的地方调用countDown即可,countDown次数达到指定次数,会唤醒所有await;
4.CyclicBarrier使用时,在每个需要等待的地方调用await,然后内部会自动统计await次数,到达指定次数后,自动回调,完成回调后,唤醒所有await。

例子1,每个任务计算一个值,都完成计算后进行下一步计算。Test2模拟了普通的计算任务,都完成后,会从latch.await()那个地方继续执行:

public class Main {
    private static final int N = 5;

    public static final void main(String[] args) {
        testCountDownLatch();
    }

    private static void testCountDownLatch() {
        CountDownLatch latch = new CountDownLatch(N);
        Test2[] tt = new Test2[N];
        for (int i = 0; i < N; i++) {
            tt[i] = new Test2(latch);
            new Thread(tt[i]).start();
        }
        System.out.println("Main is Wait.");
        try {
            latch.await();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        int total = 0;
        for (int i = 0; i < N; i++) {
            total += tt[i].ret;
        }
        System.out.println("Main is Wait Over!" + total);
    }
}

public class Test2 implements Runnable {
    private CountDownLatch latch;

    public Test2(CountDownLatch latch) {
        this.latch = latch;
    }

    public int ret = 0;

    @Override
    public void run() {
        System.out.println("Thread-" + Thread.currentThread().getName() + " is Running");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        ret = 1;
        System.out.println("Thread-" + Thread.currentThread().getName() + " is finish Task!");
        latch.countDown();

    }

}

输出结果:
Thread-Thread-1 is Running
Thread-Thread-2 is Running
Thread-Thread-3 is Running
Main is Wait.
Thread-Thread-4 is Running
Thread-Thread-0 is Running
Thread-Thread-2 is finish Task!
Thread-Thread-4 is finish Task!
Thread-Thread-3 is finish Task!
Thread-Thread-1 is finish Task!
Thread-Thread-0 is finish Task!
Main is Wait Over!5

例子2,用CountDownLatch实现的一个运动员比赛的程序:

public class Main {
    // 运动员数量
    private static final int N = 5;

    public static final void main(String[] args) {
        testCountDownLatch2();
    }

    private static void testCountDownLatch2() {
        // 运动员准备好的信号
        CountDownLatch latchStart = new CountDownLatch(N);
        // 运动员都完成比赛的信号
        CountDownLatch latchOver = new CountDownLatch(N);
        // 正式开始比赛的信号
        CountDownLatch startSignal = new CountDownLatch(1);
        for (int i = 0; i < N; i++) {
            new Thread(new Player(i, latchStart, latchOver, startSignal)).start();
        }
        System.out.println("等待运动员都准备好");
        try {
            // 等待运动员都准备好
            latchStart.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("开始比赛");
        // 开始比赛信号
        startSignal.countDown();
        try {
            // 等待所有运动员完成比赛
            latchOver.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("所有运动员都完成了比赛,比赛结束");
    }
}

public class Player implements Runnable {
    private CountDownLatch latchStart;
    private CountDownLatch latchOver;
    private CountDownLatch startSignal;

    private int id;

    private static Random sRandom = new Random();

    public Player(int id, CountDownLatch latchStart, CountDownLatch latchOver, CountDownLatch startSignal) {
        this.id = id;
        this.latchStart = latchStart;
        this.latchOver = latchOver;
        this.startSignal = startSignal;
    }

    @Override
    public void run() {
        // 模拟准备时间
        try {
            Thread.sleep(sRandom.nextInt(2000));
        } catch (InterruptedException e2) {
            e2.printStackTrace();
        }
        System.out.println("Player" + id + "准备好" + System.currentTimeMillis());
        // 运动员准备好
        this.latchStart.countDown();
        try {
            // 等待裁判说开始
            this.startSignal.await();
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        System.out.println("Player" + id + " 开始跑" + System.currentTimeMillis());
        long duration = sRandom.nextInt(5000);
        try {
            // 模拟跑的时间
            Thread.sleep(duration);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Player" + id + " 完成比赛,耗时:" + duration);
        // 运动员完成比赛
        this.latchOver.countDown();
    }

}

输出结果:
等待运动员都准备好
Player0准备好1508221461341
Player2准备好1508221461832
Player3准备好1508221462335
Player4准备好1508221462369
Player1准备好1508221463031
开始比赛
Player0 开始跑1508221463032
Player4 开始跑1508221463032
Player3 开始跑1508221463032
Player2 开始跑1508221463032
Player1 开始跑1508221463032
Player1 完成比赛,耗时:1202
Player2 完成比赛,耗时:1939
Player0 完成比赛,耗时:1947
Player4 完成比赛,耗时:2878
Player3 完成比赛,耗时:3974
所有运动员都完成了比赛,比赛结束

例子3,用CyclicBarrier实现例子1:

public class Main {
    private static final int N = 5;

    public static final void main(String[] args) {
        testCyclicBarrier();
    }

    private static void testCyclicBarrier() {
        Test3[] tt = new Test3[N];
        CyclicBarrier barrier = new CyclicBarrier(N, new Runnable() {

            @Override
            public void run() {
                // await达到指定次数,随机选一个线程来执行这个任务
                System.out.println("Barrier All Task Finished,CurrentThread=" + Thread.currentThread().getName());
                int total = 0;
                for (int i = 0; i < N; i++) {
                    total += tt[i].ret;
                }
                System.out.println("计算结果是:" + total);
            }
        });
        for (int i = 0; i < N; i++) {
            tt[i] = new Test3(barrier);
            new Thread(tt[i]).start();
        }
    }
}

public class Test3 implements Runnable {
    private CyclicBarrier barrier;

    public Test3(CyclicBarrier barrier) {
        this.barrier = barrier;
    }

    public int ret = 0;

    @Override
    public void run() {
        System.out.println("Thread-" + Thread.currentThread().getName() + " is Running");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        ret = 1;
        System.out.println("Thread-" + Thread.currentThread().getName() + " is finish Task!");
        try {
            this.barrier.await();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("Thread-" + Thread.currentThread().getName() + " exit!");

    }

}

输出结果:
Thread-Thread-1 is Running
Thread-Thread-0 is Running
Thread-Thread-3 is Running
Thread-Thread-4 is Running
Thread-Thread-2 is Running
Thread-Thread-3 is finish Task!
Thread-Thread-2 is finish Task!
Thread-Thread-1 is finish Task!
Thread-Thread-0 is finish Task!
Thread-Thread-4 is finish Task!
Barrier All Task Finished,CurrentThread=Thread-4
计算结果是:5
Thread-Thread-4 exit!
Thread-Thread-3 exit!
Thread-Thread-0 exit!
Thread-Thread-1 exit!
Thread-Thread-2 exit!

例子4,用CyclicBarrier实现例子2:

public class Main {
    private static final int N = 5;

    public static final void main(String[] args) {
        testCyclicBarrier2();
    }

    private static void testCyclicBarrier2() {
        CyclicBarrier barrierPrepare = new CyclicBarrier(N, new Runnable() {

            @Override
            public void run() {
                // 准备完成
                System.out.println("所有运动员准备完毕,开始比赛");
                
            }
        });
        CyclicBarrier barrierOver = new CyclicBarrier(N, new Runnable() {

            @Override
            public void run() {
                // 比赛完成
                System.out.println("所有运动员比赛都完成了,结束比赛");
            }
        });
        for (int i = 0; i < N; i++) {
            new Thread(new Player2(i, barrierPrepare, barrierOver)).start();
        }
    }
}

public class Player2 implements Runnable {
    private CyclicBarrier barrierPrepared;
    private CyclicBarrier barrierOver;
    private int id;
    private static Random sRandom = new Random();

    public Player2(int id, CyclicBarrier barrierPrepared, CyclicBarrier barrierOver) {
        this.barrierPrepared = barrierPrepared;
        this.barrierOver = barrierOver;
        this.id = id;
    }

    public void run() {
        try {
            // 模拟准备比赛
            Thread.sleep(sRandom.nextInt(3000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("运动员" + id + "准备比赛");
        try {
            // 等待开始
            barrierPrepared.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println("运动员" + id + "开始比赛" + System.currentTimeMillis());
        int duration = sRandom.nextInt(5000);
        try {
            // 模拟比赛耗时
            Thread.sleep(duration);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("运动员" + id + "完成比赛,比赛时长:" + duration);
        try {
            // 等待比赛结束
            barrierOver.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }

    }
}

输出结果:
运动员2准备比赛
运动员0准备比赛
运动员1准备比赛
运动员4准备比赛
运动员3准备比赛
所有运动员准备完毕,开始比赛
运动员3开始比赛1508222334484
运动员2开始比赛1508222334484
运动员1开始比赛1508222334484
运动员0开始比赛1508222334484
运动员4开始比赛1508222334484
运动员4完成比赛,比赛时长:777
运动员0完成比赛,比赛时长:2640
运动员1完成比赛,比赛时长:2952
运动员3完成比赛,比赛时长:3843
运动员2完成比赛,比赛时长:3924
所有运动员比赛都完成了,结束比赛

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容