CyclicBarrier与CountDownLatch区别

阻塞与唤醒方式的区别

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();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章