Java中CountDownLatch和CyclicBarrier

Java编程思想中的例子
import
javax.validation.constraints.Size; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; class TaskPortion implements Runnable{ private static int count; private final int id=count++; private final CountDownLatch latch; private static Random random=new Random(47); public TaskPortion(CountDownLatch latch) { this.latch = latch; } public void run() { try { doWork(); } catch (InterruptedException e) { e.printStackTrace(); } latch.countDown(); } public void doWork() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(random.nextInt(1000)); System.out.println(this+"complete"); } @Override public String toString() { return "TaskPortion: "+String.format("%1$-2d",id); } } class WaitingTask implements Runnable{ private final CountDownLatch latch; private static int count; private final int id=count++; public WaitingTask(CountDownLatch latch) { this.latch = latch; } public void run() { try { latch.await(); System.out.println(this); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public String toString() { return "waiting task pass"+String.format("%1$-2d",id); } } public class CountDownLatchDemo { private static final int SIZE=20; public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); CountDownLatch latch=new CountDownLatch(SIZE); for (int i=0;i<SIZE;i++) executorService.execute(new TaskPortion(latch)); // for (int i = 0; i < SIZE; i++) { executorService.execute(new WaitingTask(latch));
     executorService.shutdown();
    } 
  }
}

countdownlatch中有个计数器,当计数器减少到0的时候,释放所有等待的线程,coutDown()会让计数器的值减少,调用await()的线程将会进入等待状态,直到调用countdownlatch使得计数器数值减少到0,所有等待的线程都会开始执行。

CyclicBarrier

这个相对于上面的countdownlatch来说,这种可以重复的使用,而且await()已经具备countdownlatch中的countdown()和await()两种方法的作用。(前者await()被线程调用一次计数减一,后者不会,只能通过countdown())

首先了解他的构造方法。

方法

 自己独立敲了一段书上的模拟赛马的demo(来自于Java编程思想)

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;

class Horse implements Runnable{
    private CyclicBarrier barrier;               //ByclicBarrier用来控制本类的在释放屏障之前的动作,由构造函数传入
    private int stride=0;               //马跑得轨迹
    private static int count;             //马的数量
    private final int id=count++;          //设置马的id
    private Random random = new Random(47);    //模拟赛马
    
    public Horse(CyclicBarrier barrier) {
        this.barrier = barrier;
    }
    @Override
    public void run() {
       try{
           while(!Thread.interrupted()){            //这里模拟赛马的过程
               TimeUnit.MILLISECONDS.sleep(500);
            barrier.await();
            stride+=random.nextInt(3);
           }
       }catch(Exception e){
           e.printStackTrace();
        }
    }
    @Override
    public String toString() {
        return "Horse "+id+" ";
    }
    public String  getTrack(){
        StringBuilder s=new StringBuilder();//返回马当前到达屏障之后走的路径
        for (int i = 0; i < stride; i++) {
            s.append("=");
        }
        return s.toString();
    }
    public int getStride() {
        return stride;                    //马走了多少
    }

    public int getId() {
        return id;
    }
}
class HorseRace {
    private int nhorse;
    private ExecutorService exec;
    private final int FINISH_LINE = 75;
    private CyclicBarrier barrier;
    List<Horse> horses = new ArrayList<Horse>();
    private String track;
public HorseRace(int nhorse, ExecutorService executorService) { exec = executorService; this.nhorse = nhorse; StringBuilder s = new StringBuilder(); for (int i = 0; i < FINISH_LINE; i++) { s.append("="); } track = s.toString(); System.out.println(s.toString()); barrier = new CyclicBarrier(nhorse, () -> { //表达式中定义了释放屏障之前的动作,打印当前所有马的路程并且判断是否有的码已经到达终点 System.out.println(track); for (Horse horse : horses) { System.out.println(horse.getTrack()); if (horse.getStride() > FINISH_LINE) { System.out.println(horse.getId() + " won"); exec.shutdownNow(); return; } } }); for (int i = 0; i < nhorse; i++) { Horse horse = new Horse(barrier); exec.execute(horse); horses.add(horse); } } } public class HorseRaceDeno { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); new HorseRace(7, executorService); } }

 两者区别总结:

CyclicBarrier:是可以重重复使用的,只有等待线程积累到一定的数量的时候才会释放屏障,在释放屏障的时候还可以使用接口初始化CyclicBarrier变量(在里面定义释放屏障之前的动作,可以是释放线程池,终止上面所说的线程)。也可以使用只有int数据类型创建CyclicBarrier变量,这样只有在释放屏障的时候没有多余的动作。

CountDownLatch:含有两个重要的方法CountDown()和await(),前者调用一次,CountDownLatch对象就会计数减少一次。await()导致当前线程等待计数器减少到零为止,除非出现中断的情况,而且CountDownLatch只有一次的机会,只会阻塞线程一次。

触发屏障的事件不同:前者只有足够的线程调用await时候才会触发线程,后者是计数器减少到零的时候才会触发屏障,但是导致计数器减少的可能只是一个线程。

原文地址:https://www.cnblogs.com/feixiangdecainiao/p/10451369.html