CyclicBarrier

循环栅栏,用来进行线程协作,等待线程满足某个计数,构造时设置[计数个数],每个线程执行到某个需要同步的时刻调用await()方法进行等待,当等待的线程数满足【计数个数】时,继续执行

与CountDownLatch区别是可以重复使用

CyclicBarrier的计数变为0之后,再次调用await方法计数会重新变为设置值,想要重复执行任务并等待只需要创建一个对象

将任务反复运行,并且主线程将返回得到的数据进行汇总:
  1. public static void main(String[] args) {
  2. ExecutorService service = Executors.newFixedThreadPool(3);
  3. CyclicBarrier barrier = new CyclicBarrier(2, () -> {
  4. log.debug("task1, task2 finish...");
  5. });
  6. for (int i = 0; i < 3; i++) { // task1 task2 task1
  7. service.submit(() -> {
  8. log.debug("task1 begin...");
  9. sleep(1);
  10. try {
  11. barrier.await(); // 2-1=1
  12. } catch (InterruptedException | BrokenBarrierException e) {
  13. e.printStackTrace();
  14. }
  15. });
  16. service.submit(() -> {
  17. log.debug("task2 begin...");
  18. sleep(2);
  19. try {
  20. barrier.await(); // 1-1=0
  21. } catch (InterruptedException | BrokenBarrierException e) {
  22. e.printStackTrace();
  23. }
  24. });
  25. }
  26. service.shutdown();
  27. }

CountDownLatch也可以达到上述效果

  1. private static void test1() {
  2. ExecutorService service = Executors.newFixedThreadPool(5);
  3. for (int i = 0; i < 3; i++) {
  4. CountDownLatch latch = new CountDownLatch(2);
  5. service.submit(() -> {
  6. log.debug("task1 start...");
  7. sleep(1);
  8. latch.countDown();
  9. });
  10. service.submit(() -> {
  11. log.debug("task2 start...");
  12. sleep(2);
  13. latch.countDown();
  14. });
  15. try {
  16. latch.await();
  17. } catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }
  20. log.debug("task1 task2 finish...");
  21. }
  22. service.shutdown();
  23. }

CyclicBarrier注意点:

线程池中的线程数要与计数值一致,否则会有问题

如上述代码,任务1执行1s,任务2执行2s,若线程数有三个,而计数是2,则导致三个线程直接去执行两个任务1,一个任务2,当任务1时间短先执行完,返回的结果均为任务1的,而不会得到任务2的结果