JDK并发包--CountDownLatch,CyclicBarrier
CountDownLatch:
可以理解为一个计数器,这个工具通常是用来控制线程等待的,比如5个人约打球,只有等人齐了之后才能开始,这种情况适合使用CountDownLatch
public class CountDownLatchDemo implements Runnable{ static final CountDownLatch end = new CountDownLatch(5); static final CountDownLatchDemo demo = new CountDownLatchDemo(); int num = 0; @Override public void run(){ try{ synchronized(i){ num++; } Thread.sleep(new Radom().next(1000)); System.out.println(num.toString()+"boys is here..."); end.countDown(); //每个线程执行完后计数器减一 }catch(InterruptedException e){ e.printstackTrace(); } } public static main(String [] args) throws InterruptedException{ ExecutorsService exec = Executors.newFixedThreadPool(5); for(int i=0;i<5;i++){ exec.submit(demo); } end.await(); //等待5个线程执行完成 System.out.println("Let's play!"); exec.shutdown(); } }
循环栅栏(CyclicBarrier):
该类的主要方法如下:
1 //parties表示屏障拦截的线程数量,当屏障撤销时,先执行barrierAction,然后在释放所有线程 2 public CyclicBarrier(int parties, Runnable barrierAction) 3 //barrierAction默认为null 4 public CyclicBarrier(int parties) 5 6 /* 7 *当前线程等待直到所有线程都调用了该屏障的await()方法 8 *如果当前线程不是将到达的最后一个线程,将会被阻塞。解除阻塞的情况有以下几种 9 * 1)最后一个线程调用await() 10 * 2)当前线程被中断 11 3)其他正在该CyclicBarrier上等待的线程被中断 12 4)其他正在该CyclicBarrier上等待的线程超时 13 5)其他某个线程调用该CyclicBarrier的reset()方法 14 *如果当前线程在进入此方法时已经设置了该线程的中断状态或者在等待时被中断,将抛出InterruptedException,并且清除当前线程的已中断状态。 15 *如果在线程处于等待状态时barrier被reset()或者在调用await()时 barrier 被损坏,将抛出 BrokenBarrierException 异常。 16 *如果任何线程在等待时被中断,则其他所有等待线程都将抛出 BrokenBarrierException 异常,并将 barrier 置于损坏状态。 *如果当前线程是最后一个将要到达的线程,并且构造方法中提供了一个非空的屏障操作(barrierAction),那么在允许其他线程继续运行之前,当前线程将运行该操作。如果在执行屏障操作过程中发生异常,则该异常将传播到当前线程中,并将 barrier 置于损坏状态。 17 * 18 *返回值为当前线程的索引,0表示当前线程是最后一个到达的线程 19 */ 20 public int await() throws InterruptedException, BrokenBarrierException 21 //在await()的基础上增加超时机制,如果超出指定的等待时间,则抛出 TimeoutException 异常。如果该时间小于等于零,则此方法根本不会等待。 22 public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException 23 24 //将屏障重置为其初始状态。如果所有参与者目前都在屏障处等待,则它们将返回,同时抛出一个BrokenBarrierException。 25 public void reset()
这里拿一个书中的栗子,第一次计数用来确定10个士兵到齐,第二次计数用来确定10个士兵完成任务
public class CyclicBarrierDemo {
//基本士兵线程 public static class Soldier implements Runnable{ private String soldier; private final CyclicBarrier cyclic; public Soldier(CyclicBarrier cyclic,String soldierName) { this.cyclic = cyclic; this.soldier = soldierName; } public void run() { try { //等待所有士兵到齐 cyclic.await(); //第一次计数 doWork(); //等待所有士兵完成工作 cyclic.await(); //第二次计数 }catch(InterruptedException e) { e.printStackTrace(); }catch(BrokenBarrierException e) { e.printStackTrace(); } } void doWork() { try { Thread.sleep(Math.abs(new Random().nextInt()%10000)); }catch(InterruptedException e) { e.printStackTrace(); } System.out.println(soldier + ":任务完成"); } }
//每次计数完成之后需要执行的逻辑 public static class BarrierRun implements Runnable{ boolean flag; int N; public BarrierRun(boolean flag,int N) { this.flag = flag; this.N = N; } public void run(){ if(flag) { System.out.println("司令:士兵"+N+"个,任务完成"); }else { System.out.println("司令:士兵"+N+"个,集合完毕"); flag=true; } } } public static void main(String[] args) throws InterruptedException { final int N = 10; Thread[] allSoldier = new Thread[N]; //生成10个士兵线程 boolean flag = false; CyclicBarrier cyclic = new CyclicBarrier(N,new BarrierRun(flag,N)); //声明一个计数器,执行完N个线程后,执行BarrierRun,然后重置cyclic System.out.println("集合队伍"); for(int i=0;i<N;i++) { System.out.println("士兵"+i+"报道"); allSoldier[i] = new Thread(new Soldier(cyclic,"士兵"+i)); //将线程和循环栅栏绑定 allSoldier[i].start(); } } }
-----------------------------------------------------《实战Java高并发设计》笔记------------------------------------------------------