文档章节

java并发编程中CountDownLatch和CyclicBarrier的使用

zmf
 zmf
发布于 2015/09/06 16:05
字数 1364
阅读 300
收藏 2

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 {
            System.out.println("准备完毕.."+id);
            beginSignal.await();
            System.out.println("起跑..."+id);
            System.out.println("work" + id + "到达终点");
            endSignal.countDown();
            System.out.println("work" + id + "继续干其他事情");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    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 {
            Thread.currentThread().sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("-------------------------------");
        try {
            begSignal.countDown();  //统一起跑
            endSignal.await();      //等待运动员到达终点
            System.out.println("结果发送到汇报成绩的系统");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


输出结果:

准备完毕..4

准备完毕..5

准备完毕..1

准备完毕..2

准备完毕..6

准备完毕..0

准备完毕..3

准备完毕..7

-------------------------------

起跑...4

起跑...2

起跑...6

work6到达终点

起跑...1

work1到达终点

起跑...5

work5到达终点

work1继续干其他事情

work6继续干其他事情

起跑...7

work7到达终点

work7继续干其他事情

起跑...3

work3到达终点

work3继续干其他事情

起跑...0

work2到达终点

work2继续干其他事情

work4到达终点

work4继续干其他事情

work0到达终点

work0继续干其他事情

work5继续干其他事情

结果发送到汇报成绩的系统


下面详细描述下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类(玩家类)

java.util.concurrent.BrokenBarrierException
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();
        }
    }

    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();
        }
    }
}

输出结果:

玩家1正在玩第一关...

玩家2正在玩第一关...

玩家3正在玩第一关...

玩家0正在玩第一关...

所有玩家进入第二关!

玩家0进入第二关...

玩家1进入第二关...

玩家2进入第二关...

玩家3进入第二关...


© 著作权归作者所有

共有 人打赏支持
zmf

zmf

粉丝 16
博文 63
码字总数 106711
作品 0
朝阳
程序员
私信 提问
java多线程系列:通过对战游戏学习CyclicBarrier

CyclicBarrier是java.util.concurrent包下面的一个工具类,字面意思是可循环使用(Cyclic)的屏障(Barrier),通过它可以实现让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一...

huangzd
2018/01/06
0
0
新Java并发线程控制:CyclicBarrier等待所有线程到达一个状态后再让全部线程处于一个起跑线(1)

版权声明:本文为Zhang Phil原创文章,请不要转载! https://blog.csdn.net/zhangphil/article/details/83501322 新Java并发线程控制:CyclicBarrier等待所有线程到达一个状态后再让全部线程...

zhangphil
2018/10/29
0
0
Java并发编程:CountDownLatch、CyclicBarrier和Semaphore

Java并发编程:CountDownLatch、CyclicBarrier和Semaphore   在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们...

明舞
2015/09/01
0
0
【Java并发专题】27篇文章详细总结Java并发基础知识

努力的意义,就是,在以后的日子里,放眼望去全是自己喜欢的人和事! github:https://github.com/CL0610/Java-concurrency,欢迎题issue和Pull request。所有的文档都是自己亲自码的,如果觉...

你听___
2018/05/06
0
0
新Java并发线程控制:CyclicBarrier等待所有线程到达一个状态后执行一个线程动作(2)

版权声明:本文为Zhang Phil原创文章,请不要转载! https://blog.csdn.net/zhangphil/article/details/83501612 新Java并发线程控制:CyclicBarrier等待所有线程到达一个状态后执行一个线程...

zhangphil
2018/10/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

学习设计模式之路

https://java-design-patterns.com/patterns/ https://www.oodesign.com/ https://www.programering.com/a/MTNxAzMwATY.html https://design-patterns.readthedocs.io/zh_CN/latest/ https:/......

晨猫
今天
1
0
JDK1.8 jar包说明

JDK 1.8 lib:access-bridge-64.jarcharsets.jarcldrdata.jardeploy.jardnsns.jarjaccess.jarjavawa.jarjce.jarjfr.jarjfxrt.jarjfxswt.jarjsse.jarlocaledata.jar......

冷基
今天
1
0
判断用户的icloud是否开启【Swift4.2】

使用icloudkit存储用户私人数据时,必须判断用户的icloud是否开启【Swift4.2】 func isICloudContainerAvailable()-> Bool { if FileManager.default.ubiquityIdentityToken != ni......

叶落花开
今天
1
0
今天的学习

1、执行git add *命令就把改动提交到了暂存区,执行git pull命令将远程仓库的数据拉到当前分支并合并,执行git checkout [branch-name]切换分支 2、执行git commit -m '说明' 命令就把改动提...

墨冥
昨天
0
0
Android4.4 及以下TextView,Button等控件使用矢量图报错

1 问题描述 最近项目开发中,图标资源我尽量使用了矢量图,然而配置了基本的兼容设置,程序在低版本中运行还是出现了问题。 xml布局文件中,在TextView中使用矢量图,比如android:drawableS...

newtrek
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部