七、CountDownLatch和CyclicBarrier案例以及区别

CyclicBarrier和CountDownLatch 都位于java.util.concurrent 这个包下
在这里插入图片描述
总结:
CountDownLatch 主要用来解决一个线程等待多个线程的场景,可以类比旅游团团长要等待所有游客到齐才能去下一个景点。
而 CyclicBarrier 是一组线程之间的相互等待,可以类比几个驴友之间的不离不弃,共同到达某个地方,再继续出发,这样反复。

1、CountDownLatch实现并行处理最后汇总结果的功能

package day03.part3;

import java.util.concurrent.CountDownLatch;

/**
 *  向下减的门闩
 *  实现并行处理最后汇总结果的功能
 *
 * 以 汽车生产为例
 * @author xzq
 */
public class CountDownLatchTest01 {


    public static void main(String[] args) throws InterruptedException {
        final CountDownLatch cdl=new CountDownLatch(3);

        String threadName = Thread.currentThread().getName()+":";
        //创建3条线程去做这三件事
        new Thread("线程1:"){

            @Override
            public void run() {
                try {
                    productMotor();
                    cdl.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }.start();

        new Thread("线程2:"){

            @Override
            public void run() {
                try {
                    productShell();
                    cdl.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }.start();

        new Thread("线程3:"){

            @Override
            public void run() {
                try {
                    productTyre();
                    cdl.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }.start();

        //线程4为4S店派到生产厂家的监视者
        /*new Thread("线程4:"){

            @Override
            public void run() {
                try {
                    //可以有多个线程对其进行await
                    cdl.await();
                    System.out.println(Thread.currentThread().getName()+"已经生产好了一辆汽车的所有部件了!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }.start();*/

        //等待汽车各个部分生产完毕
        cdl.await();
        System.out.println(threadName+"开始组装汽车……");
        //模拟组装生产汽车需要1秒
        Thread.sleep(1000);
        System.out.println(threadName+"汽车生产完毕,运到销售中心销售。");
    }

    private static  void productMotor() throws InterruptedException{
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+"开始生产发动机……");
        //生产发动机需要5秒
        Thread.sleep(5_000);
        System.out.println(threadName+"发动机已生产完毕!");
    }

    private static void productShell() throws InterruptedException{
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+"开始生产汽车外壳……");
        //生产汽车外壳需要3秒
        Thread.sleep(3_000);
        System.out.println(threadName+"汽车外壳已生产完毕!");
    }

    private static  void productTyre() throws InterruptedException{
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+"开始生产轮胎……");
        //生产汽车轮胎需要1秒
        Thread.sleep(1_000);
        System.out.println(threadName+"轮胎已生产完毕!");
    }

}


2、CountDownLatch实现线程之间的通信

package day03.part3;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 *  向下减的门闩
 *  实现线程之间的通信
 *
 *  taobao examination
 * 实现一个容器,提供两个方法,add和size
 * 写两个线程,线程1添加10个元素到容器中,
 * 线程2实现监控元素的个数,当个数到5个时,
 * 线程2给出提示并结束
 *
 * 这里使用CountDownLatch
 * 解决这个需求
 *
 * @author xzq
 */
public class CountDownLatchTest02 {

    public static void main(String[] args) {

        final Box_5 box=new Box_5();
        final CountDownLatch latch=new CountDownLatch(1);

        new Thread("线程2"){

            @Override
            public void run() {
                try {
                    System.out.println("线程2:开始执行");
                    if(box.size()!=5){
                        latch.await();
                    }
                    System.out.println("线程2:执行完毕!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();



        new Thread("线程1"){

            @Override
            public void run() {
                try {
                    System.out.println("线程1:开始执行");
                    for(int i=1;i<=10;i++){
                        box.add(new Object());
                        System.out.println("线程1:add第"+i+"个元素");
                        if(box.size()==5){
                            latch.countDown();
                            System.out.println("线程1:已经有5个元素啦!");
                        }
                        Thread.sleep(1_000);
                    }
                    System.out.println("线程1:执行完毕!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();


    }

}


/**
 * 加上volatile后使box的修改可以得到通知
 *
 * @author Peter
 */
class Box_5{

    private volatile List<Object> box=new ArrayList<>();

    public void add(Object element){
        box.add(element);
    }

    public int size(){
        return box.size();
    }

}


3、CountDownLatchAPI的使用讲解

package day03.part3;

import java.util.concurrent.CountDownLatch;

/**
 *  向下减的门闩
 *  API的使用讲解
 *
 * @author xzq
 */
public class CountDownLatchTest03 {

    public static void main(String[] args) throws InterruptedException {

        final CountDownLatch cdl=new CountDownLatch(1);//为0时、为-1时

        new Thread("子线程:"){

            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName+"开始造原子弹……");
                //做造原子弹需要做20秒
                try {
                    Thread.sleep(20_000);
                    cdl.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(threadName+"原子弹制造完毕!");
            }

        }.start();

        //主线程去等待子线程做完某事在往下执行
        System.out.println("主线程:开始等待子线程……");
        //如果先countDown再进行await,那么就没有效果
//      cdl.countDown();
        cdl.await();
        //await的效果不能叠加
//      cdl.await();

        //设置超时时间,超过这个时间就不再等待了
//      System.out.println("主线程:我只等2秒,2秒后还造不出原子弹,我就不等了!");
//      cdl.await(2, TimeUnit.SECONDS);
//      System.out.println("主线程:我已经等了2秒了,还没造出原子弹,不等了,开始打仗吧!");

        System.out.println("主线程:执行完毕!");
    }

}


4、CountDownLatch对中断的处理

package day03.part3;

import java.util.concurrent.CountDownLatch;

/**
 *  向下减的门闩
 *  API的使用讲解
 *  对中断的处理
 * @author xzq
 */
public class CountDownLatchTest04 {

    public static void main(String[] args) {

        final Thread mainThread=Thread.currentThread();

        final CountDownLatch cdl=new CountDownLatch(1);

        new Thread("子线程:"){

            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName+"开始造原子弹……");
                //做造原子弹需要做20秒
                try {
                    Thread.sleep(3_000);
                    System.out.println("3秒后中断正在await的主线程,告诉他不要等了");
                    mainThread.interrupt();
                    Thread.sleep(17_000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(threadName+"原子弹制造完毕!");
            }

        }.start();

        //主线程去等待子线程做完某事在往下执行
        System.out.println("主线程:开始等待子线程……");
        try {
            cdl.await();
        } catch (InterruptedException e) {
            System.out.println("主线程:被通知到不要等了,原子弹不是3秒钟就能造出来的!");
        }
        System.out.println("主线程:执行完毕!");
    }

}


CyclicBarrier: 1

package day03.part3;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * 栅栏:本人比喻为:检测站
 * @author xzq
 */
public class CyclicBarrierTest01 {

    public static void main(String[] args) throws InterruptedException {

        //公司要在北京开董事会,公司总共3个董事
        final CyclicBarrier barrier=new CyclicBarrier(3);

        /*final CyclicBarrier barrier=new CyclicBarrier(3,new  Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"所有人已到达北京,召开董事会!");
            }
        });*/


        //创建3个董事线程
        for(int i=1;i<=3;i++){
            new Thread("董事"+i+":"){
                @Override
                public void run() {
                    try {
                        String threadName = Thread.currentThread().getName();
                        System.out.println(threadName+"出发前往北京……");
                        //董事1到达北京需要1秒
                        if("董事1:".equals(threadName)){
                            Thread.sleep(1000);
                        }else if("董事2:".equals(threadName)){//董事2到达北京需要3秒
                            Thread.sleep(3000);
                        }else{//董事3到达北京需要4秒
                            Thread.sleep(4000);
                        }
                        System.out.println(threadName+"已到达北京!");
                        //getNumberWaiting方法,当调用await之后这个数字就会减1
                        int waittingNum =barrier.getNumberWaiting();
                        System.out.println(threadName+"当前有"+(waittingNum+1)+"个董事到达北京。");
                        barrier.await();
                        //每一个董事都知道自己到达后自己还需不需要等待
                        System.out.println(threadName+"总共需要"+barrier.getParties()+"人才能开董事会!");
                        if(waittingNum==0){
                            System.out.println(threadName+"所有人已经到达北京,召开董事会!");
                        }
                    } catch (InterruptedException | BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }

    }

}


CyclicBarrier: 2、对中断的处理

package day03.part3;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * 栅栏:本人比喻为:检测站
 * 对中断的处理
 * @author xzq
 */
public class CyclicBarrierTest02 {

    public static void main(String[] args) throws InterruptedException {

        //公司要在北京开董事会,公司总共3个董事
        final CyclicBarrier barrier=new CyclicBarrier(3);

        Thread t1 = new Thread("董事1:"){
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                try {
                    System.out.println(threadName+"出发前往北京……");
                    //董事1到达北京需要1秒
                    Thread.sleep(1000);
                    System.out.println(threadName+"已到达北京!");
                    //getNumberWaiting方法,当调用await之后这个数字就会减1
                    int waittingNum =barrier.getNumberWaiting();
                    barrier.await();
                    if(waittingNum==0){
                        System.out.println(threadName+"所有人已经到达北京,召开董事会!");
                    }
                } catch (InterruptedException e) {
                    System.out.println(threadName+"我被杀掉了!");
                } catch (BrokenBarrierException e) {
                    System.out.println(threadName+"有董事被杀掉了!");
                }
            }
        };

        Thread t2 = new Thread("董事2:"){
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                try {
                    System.out.println(threadName+"出发前往北京……");
                    //董事2到达北京需要2秒
                    Thread.sleep(2000);
                    System.out.println(threadName+"已到达北京!");
                    //getNumberWaiting方法,当调用await之后这个数字就会减1
                    int waittingNum =barrier.getNumberWaiting();
                    System.out.println(threadName+"此时isBroken的状态为:"+barrier.isBroken());
                    barrier.await();
                    if(waittingNum==0){
                        System.out.println(threadName+"所有人已经到达北京,召开董事会!");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    System.out.println(threadName+"有董事被杀掉了!");
                }
            }
        };

        Thread t3 = new Thread("董事3:"){
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                try {
                    System.out.println(threadName+"出发前往北京……");
                    //董事3到达北京需要4秒
                    Thread.sleep(4000);
                    System.out.println(threadName+"已到达北京!");
                    //getNumberWaiting方法,当调用await之后这个数字就会减1
                    int waittingNum =barrier.getNumberWaiting();
                    System.out.println(threadName+"此时isBroken的状态为:"+barrier.isBroken());
                    barrier.await();
                    if(waittingNum==0){
                        System.out.println(threadName+"所有人已经到达北京,召开董事会!");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    System.out.println(threadName+"有董事被杀掉了!");
                }
            }
        };
        t1.start();
        t2.start();
        t3.start();
        //主线程在2.5秒后中断董事1
        Thread.sleep(2500);
        t1.interrupt();
        System.out.println("主线程执行完毕!");
    }

}

CyclicBarrier: 3、使用reset方法

package day03.part3;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * 栅栏:本人比喻为:检测站
 * 使用reset方法
 * @author xzq
 */
public class CyclicBarrierTest03 {

    public static void main(String[] args) throws InterruptedException, BrokenBarrierException {

        //公司要在北京开董事会,公司总共3个董事
        final CyclicBarrier barrier=new CyclicBarrier(3);

        Thread t1 = new Thread("董事1:"){
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                try {
                    System.out.println(threadName+"出发前往北京……");
                    //董事1到达北京需要1秒
                    Thread.sleep(1000);
                    System.out.println(threadName+"已到达北京!");
                    //getNumberWaiting方法,当调用await之后这个数字就会减1
                    int waittingNum =barrier.getNumberWaiting();
                    barrier.await();
                    if(waittingNum==0){
                        System.out.println(threadName+"所有人已经到达北京,召开董事会!");
                    }
                } catch (InterruptedException e) {
                } catch (BrokenBarrierException e) {
                }
            }
        };

        Thread t2 = new Thread("董事2:"){
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                try {
                    System.out.println(threadName+"出发前往北京……");
                    //董事2到达北京需要2秒
                    Thread.sleep(2000);
                    System.out.println(threadName+"已到达北京!");
                    //getNumberWaiting方法,当调用await之后这个数字就会减1
                    int waittingNum =barrier.getNumberWaiting();
                    barrier.await();
                    if(waittingNum==0){
                        System.out.println(threadName+"所有人已经到达北京,召开董事会!");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                }
            }
        };

        Thread t3 = new Thread("董事3:"){
            @Override
            public void run() {
                String threadName = Thread.currentThread().getName();
                try {
                    System.out.println(threadName+"出发前往北京……");
                    //董事3到达北京需要4秒
                    Thread.sleep(4000);
                    System.out.println(threadName+"已到达北京!");
                    //getNumberWaiting方法,当调用await之后这个数字就会减1
                    int waittingNum =barrier.getNumberWaiting();
                    barrier.await();
                    if(waittingNum==0){
                        System.out.println(threadName+"所有人已经到达北京,召开董事会!");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                }
            }
        };
        t1.start();
        t2.start();
        t3.start();
        //主线程在1.5秒后调用reset方法,表示自己也要参加董事会
        Thread.sleep(1500);
        System.out.println("主线程:已经有"+barrier.getNumberWaiting()+"个董事到达北京!");
        barrier.reset();//将倒计时重置
        //主线程花了2秒到达北京
        Thread.sleep(2000);
        System.out.println("主线程:已经到达北京!");
        barrier.await();
        System.out.println("主线程执行完毕!");
    }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值