CyclicBarrier与CountDownLatch区别

来源:互联网 发布:java中instanceof 编辑:程序博客网 时间:2024/05/17 04:39

阻塞与唤醒方式的区别

CountDownLatch计数方式

CountDownLatch是减计数。调用await()后线程阻塞。调用countDown()方法后计数减一,当计数为零时,调用await()的线程被唤醒。

CountDownLatch应用场景为:

一个或一组线程等待另一组线程完成操作后恢复执行

CountDownLatch例子: 模拟赛跑

开始时一组运动员线程等待begin计数器(初始值为1),当主线程调用begin.countDown()后begin减1,计数器为0,这一组运动员线程同时起跑。主线程等待end计数器(初始值为10)。一个运动员线程到达终点后,调用end.countDown(),end计数器减1。当所有运动员都到达终点后,end计数器为0,主线程恢复执行。

package CountDownLatch;import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class RaceSimulation {    public static void main(String args[]){        //比赛开始的倒数锁        CountDownLatch begin=new CountDownLatch(1);        //比赛结束的倒数锁        CountDownLatch end=new CountDownLatch(10);        //十个选手跑步线程        final ExecutorService exec = Executors.newFixedThreadPool(10);        for(int index= 0;index<10;++index){            final int NO=index+1;            Runnable run = new Runnable(){                @Override                public void run() {                    try{                        //如果计数不为0,则一直等待                        //如果当前计数为0,此线程立即执行                        begin.await();                        Thread.sleep((long)(Math.random()*10000));                        System.out.println("No."+NO+" arrived");                    }catch(InterruptedException e){                        e.printStackTrace();                    }finally{                        //每个选手到达终点时,end就减1                        end.countDown();                    }                }            };            exec.submit(run);        }        System.out.println("游戏开始:");        //begin减1,开始游戏        begin.countDown();        //等待end变为0,即所有选手到达终点        try {            end.await();        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("游戏结束");        exec.shutdown();    }}

CyclicBarrier计数方式

CyclicBarrier是加计数。调用await()后线程阻塞计数器加1,当所有线程都到达屏障被阻塞后,这一组线程才一起恢复执行。

CyclicBarrier的应用场景

一组线程到达一个屏障(即执行CyclicBarrier.await())时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。

CyclicBarier的例子

package cyclicBarrier;import java.util.Random;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class CyclicBarrierDemo {    public static void main(String[] args) {        int N=4;        CyclicBarrier cyclicBarrier=new CyclicBarrier(N,new Runnable() {            @Override            public void run() {                System.out.println("线程"+Thread.currentThread().getName()+"正在执行所有线程到达屏障后执行的操作");            }        });        ExecutorService exec=Executors.newFixedThreadPool(4);        for(int i=0;i<N;++i) {            Runnable r=()->{                try {                    System.out.println("线程"+Thread.currentThread().getName()+"正在执行线程的操作");                    //用睡眠代替线程的操作                    Thread.sleep(new Random().nextInt(1000));                    System.out.println("线程"+Thread.currentThread().getName()+"到达屏障");                    cyclicBarrier.await();                    System.out.println("线程"+Thread.currentThread().getName()+"越过屏障,线程执行完毕");                } catch (InterruptedException e) {                    e.printStackTrace();                } catch (BrokenBarrierException e) {                    e.printStackTrace();                }           };           exec.submit(r);        }        exec.shutdown();    }}

是否可以重用

  1. CountDownLatch不可以重用

  2. CyclicBarrier可以重用

package cyclicBarrier;import java.util.Random;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class CyclicBarrierDemo {    public static void main(String[] args) {        int N=4;        CyclicBarrier cyclicBarrier=new CyclicBarrier(N,new Runnable() {            @Override            public void run() {                System.out.println("线程"+Thread.currentThread().getName()+"正在执行所有线程到达屏障后执行的操作");            }        });        ExecutorService exec1=Executors.newFixedThreadPool(4);        for(int i=0;i<N;++i) {            Runnable r=()->{                try {                    System.out.println("线程"+Thread.currentThread().getName()+"正在执行线程的操作");                    //用睡眠代替线程的操作                    Thread.sleep(new Random().nextInt(1000));                    System.out.println("线程"+Thread.currentThread().getName()+"到达屏障");                    cyclicBarrier.await();                    System.out.println("线程"+Thread.currentThread().getName()+"越过屏障,线程执行完毕");                } catch (InterruptedException e) {                    e.printStackTrace();                } catch (BrokenBarrierException e) {                    e.printStackTrace();                }           };           exec1.submit(r);        }        exec1.shutdown();        try {            Thread.sleep(5000);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("CyclicBarrier重用");        ExecutorService exec2=Executors.newFixedThreadPool(4);        for(int i=0;i<N;++i) {            Runnable r=()->{                try {                    System.out.println("线程"+Thread.currentThread().getName()+"正在执行线程的操作");                    //用睡眠代替线程的操作                    Thread.sleep(new Random().nextInt(1000));                    System.out.println("线程"+Thread.currentThread().getName()+"到达屏障");                    cyclicBarrier.await();                    System.out.println("线程"+Thread.currentThread().getName()+"越过屏障,线程执行完毕");                } catch (InterruptedException e) {                    e.printStackTrace();                } catch (BrokenBarrierException e) {                    e.printStackTrace();                }           };           exec2.submit(r);        }        exec2.shutdown();    }}
原创粉丝点击