多线程屏障CyclicBarrier

文章目录

  • 前言
  • 一、CyclicBarrier可以做什么?
  • 二、使用步骤
    • 1 单参数CyclicBarrier
    • 2 多参数 CyclicBarrier
    • 3 与CyclicBarrier类似的Exchanger
  • 总结


前言

多线程中的CyclicBarrier,同样也是juc包下的一个工具类;


一、CyclicBarrier可以做什么?

CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞;
意思就是:

  • 当我创建CyclicBarrier 的时候,入参就是屏障拦截线程的个数;
  • 当没有达到这个屏障拦截个数的时候,那么所有线程均被阻塞
  • 每个线程调用 CyclicBarrier 的 await(); 算是告诉 CyclicBarrier 到达了屏障

二、使用步骤

1 单参数CyclicBarrier

例如如下代码:

public class CyclicBarrierTest{

    /**
     * int 入参   其参数表示屏障拦截的线程数量,
     * 每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞
     * 只有线程的阻塞数量(到达屏障的数量) 与int 入参相当的时候,线程才会进入就绪状态,开始执行
     */
    static CyclicBarrier cyclicBarrier = new CyclicBarrier(2);

    @SneakyThrows
    public static void main(String[] args) {


        new Thread(() -> {
            try {
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (BrokenBarrierException e) {
                throw new RuntimeException(e);
            }
            System.out.println("我是子线程");
        }).start();

        cyclicBarrier.await();
        System.out.println("我是主线程");

    }
}
  1. 其中创建CyclicBarrier 的时候入参为2
  2. 那么只有当有2 个线程调用了 CyclicBarrier 的 await()方法的时候,才会真正执行,否则一直被阻塞;
  3. 当 static CyclicBarrier cyclicBarrier = new CyclicBarrier(3); 那么执行这个方法,会一直阻塞,因为没有第三个线程调用 await() 方法;

多线程屏障CyclicBarrier_第1张图片
当改为3 之后

多线程屏障CyclicBarrier_第2张图片
说明两个线程均被阻塞,正在等待第三个线程到达屏障,才会继续执行;

2 多参数 CyclicBarrier

例如如下代码:

public class CyclicBarrierPriority {

    static CyclicBarrier cyclicBarrier = new CyclicBarrier(2,() -> System.out.println("我先执行"));

    @SneakyThrows
    public static void main(String[] args) {

        new Thread(() -> {
            try {
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (BrokenBarrierException e) {
                throw new RuntimeException(e);
            }
            System.out.println("1");
        }).start();

        cyclicBarrier.await();
        System.out.println("2");

    }
}
  1. 第一个参数 与第一种相同,都是等待达到屏障的线程目标数量
  2. 第二个参数是 一个线程,它是一个最优先执行的线程; 当符合屏障数量之后,先执行第二个参数 也就是这个线程;

多线程屏障CyclicBarrier_第3张图片
当入参中的第一个参数改为 3
那么这个线程永远不会执行,与之前类似,因为不会有第三个线程达到屏障,所以一直阻塞所有线程;

3 与CyclicBarrier类似的Exchanger

感觉应用场景不多,所以不单独写一片了,就在此处补充下; Exchanger与线程屏障功能类似,不通的是,它不是通过计数的形式,而是通过是否得到交换信息而实现的;

代码如下:

public class 线程交换信息 {


    @SneakyThrows
    public static void main(String[] args) {

        Exchanger stringExchanger = new Exchanger<>();

        Thread thread = new Thread(() -> {
            System.out.println(Thread.currentThread().getName());
            try {
                System.out.println(Thread.currentThread().getName() + "我接受到了消息: " + stringExchanger.exchange("你好"));
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        thread.setName("第一个");
        thread.start();

        Thread.sleep(2000);
        Thread thread1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName());
            try {
                System.out.println(Thread.currentThread().getName() + "我接受到了消息: " + stringExchanger.exchange("hello"));
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        thread1.setName("第二个");
        thread1.start();

    }
}

当第二个线程不运行的时候,第一个线程就会一直阻塞
直到有第二个线程与它进行信息交换后,两个线程才会继续运行
如果两个线程有一个没有执行exchange()方法,则会一直等待,如果担心有特殊情况发生,避免一直等待,可以使用exchange(V x,longtimeout,TimeUnit unit)设置最大等待时长;


总结

CyclicBarrier可以用于多线程计算数据,最后合并计算结果的场景; 与这篇文章类似:
多线程处理有序集合

你可能感兴趣的:(多线程,java,jvm,算法)