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时候才会触发线程,后者是计数器减少到零的时候才会触发屏障,但是导致计数器减少的可能只是一个线程。