Java NIO - CyclicBarrier

来源:互联网 发布:知乎 编程电脑配置要求 编辑:程序博客网 时间:2024/05/16 05:17

CountDownLatch是一次性的,CyclicBarrier可以循环使用,允许一组线程互相等待,直到公共的common barrier point。common barrier point就是一组任务执行完毕的时候。

  1. package chp4.cyclicBarrier;
  2. import java.util.concurrent.BrokenBarrierException;
  3. import java.util.concurrent.CyclicBarrier;
  4. public class CyclicBarrierDemo {
  5. final CyclicBarrier barrier;
  6. final int MAX_TASK;
  7. public CyclicBarrierDemo(int cnt) {
  8. barrier = new CyclicBarrier(cnt + 1);
  9. MAX_TASK = cnt;
  10. }
  11. public void doWork(final Runnable work) {
  12. new Thread() {
  13. @Override
  14. public void run() {
  15. work.run();
  16. try {
  17. int index = barrier.await();
  18. System.out.println("doWork index: " + index);
  19. doWithIndex(index);
  20. } catch (InterruptedException e) {
  21. return;
  22. } catch (BrokenBarrierException e) {
  23. return;
  24. }
  25. }
  26. }.start();
  27. }
  28. private void doWithIndex(int index) {
  29. System.out.println("doWithIndex index: " + index);
  30. if (index == MAX_TASK / 3) {
  31. System.out.println("Left 30%.");
  32. } else if (index == MAX_TASK / 2) {
  33. System.out.println("Left 50%");
  34. } else if (index == 0) {
  35. System.out.println("run over");
  36. }
  37. }
  38. public void waitForNext() {
  39. try {
  40. int index = barrier.await();
  41. System.out.println("waitForNext index: " + index);
  42. doWithIndex(index);
  43. } catch (InterruptedException e) {
  44. return;
  45. } catch (BrokenBarrierException e) {
  46. return;
  47. }
  48. }
  49. public static void main(String[] args) {
  50. final int count = 10;
  51. CyclicBarrierDemo demo = new CyclicBarrierDemo(count);
  52. for (int i = 0; i < 100; i++) {
  53. demo.doWork(new Runnable() {
  54. public void run() {
  55. System.out.println("main thread, currentThread:" + Thread.currentThread().getId());
  56. try {
  57. Thread.sleep(1000L);
  58. } catch (Exception e) {
  59. return;
  60. }
  61. }
  62. });
  63. if ((i + 1) % count == 0) {
  64. demo.waitForNext();
  65. }
  66. }
  67. }
  68. }

清单1描述的是一个周期性处理任务的例子,在这个例子中有一对的任务(100个),希望每10个为一组进行处理,当前仅当上一组任务处理完成后才能进行下一组,另外在每一组任务中,当任务剩下50%,30%以及所有任务执行完成时向观察者发出通知。

在这个例子中,CyclicBarrierDemo 构建了一个count+1的任务组(其中一个任务时为了外界方便挂起主线程)。每一个子任务里,人物本身执行完毕后都需要等待同组内其它任务执行完成后才能继续。同时在剩下任务50%、30%已经0时执行特殊的其他任务(发通知)。

很显然CyclicBarrier有以下几个特点:

  • await()方法将挂起线程,直到同组的其它线程执行完毕才能继续
  • await()方法返回线程执行完毕的索引,注意,索引时从任务数-1开始的,也就是第一个执行完成的任务索引为parties-1,最后一个为0,这个parties为总任务数,清单中是cnt+1
  • CyclicBarrier 是可循环的,显然名称说明了这点。在清单1中,每一组任务执行完毕就能够执行下一组任务。

另外除了CyclicBarrier除了以上特点外,还有以下几个特点:

  • 如果屏障操作不依赖于挂起的线程,那么任何线程都可以执行屏障操作。在清单1中可以看到并没有指定那个线程执行50%、30%、0%的操作,而是一组线程(cnt+1)个中任何一个线程只要到达了屏障点都可以执行相应的操作
  • CyclicBarrier 的构造函数允许携带一个任务,这个任务将在0%屏障点执行,它将在await()==0后执行。
  • CyclicBarrier 如果在await时因为中断、失败、超时等原因提前离开了屏障点,那么任务组中的其他任务将立即被中断,以InterruptedException异常离开线程。
  • 所有await()之前的操作都将在屏障点之前运行,也就是CyclicBarrier 的内存一致性效果

 

CyclicBarrier 的所有API如下:

  • public CyclicBarrier(int parties) 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。
  • public CyclicBarrier(int parties, Runnable barrierAction) 创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。
  • public int await() throws InterruptedException, BrokenBarrierException 在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
  • public int await(long timeout,TimeUnit unit) throws InterruptedException, BrokenBarrierException,TimeoutException 在所有参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。
  • public int getNumberWaiting() 返回当前在屏障处等待的参与者数目。此方法主要用于调试和断言。
  • public int getParties() 返回要求启动此 barrier 的参与者数目。
  • public boolean isBroken() 查询此屏障是否处于损坏状态。
  • public void reset() 将屏障重置为其初始状态。



参考:http://www.blogjava.net/xylz/archive/2010/07/12/325913.html

0 0