Java线程同步器之CyclicBarrier以及原理简单分析

功能

它可以让一组线程全部达到一个状态之后全部同时执行。

回环屏障

回环:所有等待的线程执行完毕,重置CyclicBarrier状态后它可以被重用。
屏障:线程调用await方法后会被阻塞,这个阻塞点称为屏障点,所有子线程都调用了await方法之后,子线程就会冲破屏障点,继续运行。

案例
package concurrentProgramming;

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

public class CyclicBarrierTest1 {
    //创建一个CyclicBarrier实例线程,当所有的子线程都达到一个屏障之后会运行该线程
    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread()+"子线程已经达到屏障点!");
        }
    });

    public static void main(String[] args) {
        //创建一个线程个数固定为2的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //创建第一个子线程1
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread()+"子线程1");
                    System.out.println(Thread.currentThread()+"子线程1进入barrier!");

                    //子线程1的屏障点
                    cyclicBarrier.await();

                    System.out.println(Thread.currentThread()+"子线程1结束Barrier!");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        //创建第一个子线程2
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread()+"子线程2");
                    System.out.println(Thread.currentThread()+"子线程2进入barrier!");
                    //子线程2的屏障点
                    cyclicBarrier.await();

                    System.out.println(Thread.currentThread()+"子线程2结束Barrier!");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        //关闭线程池
        executorService.shutdown();
    }
}

运行结果:

Thread[pool-1-thread-1,5,main]子线程1
Thread[pool-1-thread-2,5,main]子线程2
Thread[pool-1-thread-2,5,main]子线程2进入barrier!
Thread[pool-1-thread-1,5,main]子线程1进入barrier!
Thread[pool-1-thread-1,5,main]子线程已经达到屏障点!
Thread[pool-1-thread-1,5,main]子线程1结束Barrier!
Thread[pool-1-thread-2,5,main]子线程2结束Barrier!

由上述案例可以得知当所有的子线程都调用await方法之后就已经到达屏障点,此时会运行CyclicBarrier实例化时构造函数传入的线程。

案例2

假设有如下要求

  • 每个任务有三个阶段,阶段1,阶段2,阶段3。
  • 每个线程要串行的执行阶段1,阶段2,阶段2。
  • 多个线程同时执行该任务时,只有每个任务的阶段1都执行完之后,才能执行阶段2,每个任务的阶段2全部执行完之后才能执行阶段3。

代码实现:

package concurrentProgramming;

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

public class CyclicBarrierTest2 {
    private static CyclicBarrier  cyclicBarrier = new CyclicBarrier(2);

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //创建线程1
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread()+"step1");
                    cyclicBarrier.await();
                    System.out.println(Thread.currentThread()+"step2");
                    cyclicBarrier.await();
                    System.out.println(Thread.currentThread()+"step3");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        //创建线程2
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println(Thread.currentThread()+"step1");
                    cyclicBarrier.await();
                    System.out.println(Thread.currentThread()+"step2");
                    cyclicBarrier.await();
                    System.out.println(Thread.currentThread()+"step3");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        executorService.shutdown();
    }
}

运行结果:

Thread[pool-1-thread-1,5,main]step1
Thread[pool-1-thread-2,5,main]step1
Thread[pool-1-thread-1,5,main]step2
Thread[pool-1-thread-2,5,main]step2
Thread[pool-1-thread-1,5,main]step3
Thread[pool-1-thread-2,5,main]step3

Process finished with exit code 0
原理探究
构造函数
    public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }
    public CyclicBarrier(int parties) {
        this(parties, null);
    }

成员变量:

  /** The lock for guarding barrier entry */
    private final ReentrantLock lock = new ReentrantLock();
    /** Condition to wait on until tripped */
    private final Condition trip = lock.newCondition();
    /** The number of parties */
    private final int parties;
    /* The command to run when tripped */
    private final Runnable barrierCommand;
    /** The current generation */
    private Generation generation = new Generation();

CyclicBarrier也是基于独占锁实现的,本质底层还是基于AQS的。
parties用来记录线程数,这里表示多少线程调用await之后,所有线程才会冲破屏障继续往下运行。
trip 独占锁的条件变量,通过条队列来实现线程同步。

主要方法
int await()

当线程调用该方法是就会被阻塞,直到满足一下条件就会返回:

  • parties个线程调用了await方法,线程达到屏障点
  • 其他线程中断当前线程,抛出异常
  • 关联的Generation 对象的broken标志被置为true时,抛出异常。
boolean await(long timeOut , TimeUnit unit)

和上一个方法类似,但是返回值发生变化,并且超时之后会返回false。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值