JUC并发编程 共享模式之工具 JUC CyclicBarrier(循环栅栏 与CountdownLatch最大的不同是可以重值倒计时) -- CyclicBarrier介绍使用注意事项

Posted Z && Y

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC并发编程 共享模式之工具 JUC CyclicBarrier(循环栅栏 与CountdownLatch最大的不同是可以重值倒计时) -- CyclicBarrier介绍使用注意事项相关的知识,希望对你有一定的参考价值。

1. CyclicBarrier介绍

循环栅栏,用来进行线程协作,等待线程满足某个计数。构造时设置『计数个数』,每个线程执行到某个需要“同步”的时刻调用 await() 方法进行等待,当等待的线程数满足『计数个数』时,继续执行。与CountdownLatch最大的不同是可以重值倒计时

CountDownLatch问题说明: CountDownLatch想要重置倒计时就只有重新创建一个新的对象

private static void test1() {
        ExecutorService service = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 3; i++) {
            // CountDownLatch想要重置倒计时就只有重新创建一个新的对象
            CountDownLatch latch = new CountDownLatch(2);
            service.submit(() -> {
                log.debug("task1 start...");
                sleep(1);
                latch.countDown();
            });
            service.submit(() -> {
                log.debug("task2 start...");
                sleep(2);
                latch.countDown();
            });
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("task1 task2 finish...");
        }
        service.shutdown();
    }

2. CyclicBarrier使用

示例代码:

package com.tian;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j(topic = "c.TestCyclicBarrier")
public class TestCyclicBarrier {

    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(2);
        CyclicBarrier barrier = new CyclicBarrier(2,
                // 这个参数是倒计时为0后执行的线程任务
                () -> {
                    log.debug("task1, task2 finish...");
                });
        for (int i = 0; i < 3; i++) { 
            service.submit(() -> {
                log.debug("task1 begin...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    log.debug("task1 end...");
                    barrier.await(); // 2-1=1
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
            service.submit(() -> {
                log.debug("task2 begin...");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    log.debug("task2 end...");
                    barrier.await(); // 1-1=0
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }
        service.shutdown();
    }
}

运行结果:

说明:

每次调用await方法都会使计数器减一,当计数器到0后,再次调用await方法就会重置计数器为初始值,这样就达到了循环的效果(与CountdownLatch最大的不同是可以重值倒计时)


3. 注意事项

要想达到上面的运行效果,需要线程池的核心线程数量与倒计时一致。否则就会出现task1 task2 task1 ,task1重复重置倒计时的效果(因为task1的睡眠时间比task2短)

示例:不一致的效果:



以上是关于JUC并发编程 共享模式之工具 JUC CyclicBarrier(循环栅栏 与CountdownLatch最大的不同是可以重值倒计时) -- CyclicBarrier介绍使用注意事项的主要内容,如果未能解决你的问题,请参考以下文章

JUC并发编程 共享模式之工具 JUC Semaphore(信号量) -- 介绍 & 使用

JUC并发编程 共享模式之工具 JUC ConcurrentHashMap -- ConcurrentHashMap的错误使用和正确使用(示例:统计单词个数)

JUC并发编程 共享模式之工具 JUC Semaphore(信号量) -- Semaphore原理

JUC并发编程 共享模式之工具 JUC 线程安全的集合类 -- 线程安全的集合类概述

JUC并发编程 共享模式之工具 ThreadPoolExecutor -- 正确处理线程池异常

JUC并发编程 共享模式之工具 JUC 读写锁 ReentrantReadWriteLock -- ReentrantReadWriteLock(不可重入锁)使用 & 注意事项