java 多线程-障栅CyclicBarrier

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。


public class Test{
	public static void main(String[] arg){

		//新建一个障栅,其会阻拦10个线程
		CyclicBarrier cyclicBarrier = new CyclicBarrier(10);

		ThreadGroup group = new ThreadGroup("semaphore");//自定义线程组
		AtomicInteger num = new AtomicInteger(0);

		ThreadPoolExecutor pool = new ThreadPoolExecutor(
				10, 
				10, 
				1000, 
				TimeUnit.SECONDS, 
				new LinkedBlockingDeque<Runnable>(20), new ThreadFactory() {//线程池工厂
					@Override
					public Thread newThread(Runnable r) {//生产新的线程
						Thread thread = new Thread(group, r, group.getName()+"-thread-"+num.getAndIncrement());
						thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
							@Override
							public void uncaughtException(Thread t, Throwable e) {
								System.out.println(t.getName()+"发生异常:"+e.getMessage());
							}
						});
						return thread;
					}
				},new RejectedExecutionHandler() {//线程池的拒绝策略
					@Override
					public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
						throw new RuntimeException("任务队列已满,任务被拒绝");
					}
				});

		//定义任务
		Runnable task = ()->{

			System.out.println("遇到了障栅....."+Thread.currentThread().getName()+"即将被阻塞");

			try {

				cyclicBarrier.await();
				System.out.println("障栅放开了....."+Thread.currentThread().getName()+"即将休眠");
				Thread.sleep(3000);

			} catch (InterruptedException | BrokenBarrierException e) {
				e.printStackTrace();
			}

		};


		try {
			Thread.sleep(8000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}


		for(int i = 0; i < 10; i++){//循环运行10个任务
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			pool.execute(task);
		}

		if(Thread.activeCount() > 1){
			Thread.yield();
		}
		pool.shutdown();
	}
}


此外 CyclicBarrier提供了两个构造函数:

1:CyclicBarrier(int parties):创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动

2:CyclicBarrier(int parties, Runnable barrierAction) :创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行(即最后一个到达障栅点的线程执行参数中的barrierAction)

实例程序如下:

public class Test {

	//使用工厂方法来创建 阻塞队列 ,实现解耦操作
	private static class QueueFactory{
		public static BlockingQueue getInstance(){
			return new LinkedBlockingQueue<>();
		}
	}

	public static void main(String[] args) {

		//定义一个含有Runnable参数的,大小为3 的障栅
		CyclicBarrier b = new CyclicBarrier(3,new Runnable() {
			@Override
			public void run() {
				//最后一个到达障栅点的线程将执行此方法
				System.out.println(Thread.currentThread().getName()+"----I am coming...");
			}
		});

		//新建一个线程池 来跑线程
		ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3,
				5,
				1000,
				TimeUnit.SECONDS,
				QueueFactory.getInstance());

		Runnable aRunnable = new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+"----I am waiting...");
					b.await();
				} catch (InterruptedException|BrokenBarrierException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"----I am running...");
			}
		};

		poolExecutor.execute(aRunnable);
		poolExecutor.execute(aRunnable);
		poolExecutor.execute(aRunnable);

		poolExecutor.shutdown();
	}
}

输出结果:

pool-1-thread-1----I am waiting...
pool-1-thread-3----I am waiting...
pool-1-thread-2----I am waiting...
pool-1-thread-2----I am coming... //最后一个到达障栅点的线程说了一句 I am coming...
pool-1-thread-2----I am running...
pool-1-thread-3----I am running...
pool-1-thread-1----I am running...



其实障栅的原理是Condition下面,我用Condition实现障栅的效果

public class Test {
	//使用工厂方法来创建 阻塞队列 ,实现解耦操作
	private static class QueueFactory{
		public static BlockingQueue getInstance(){
			return new LinkedBlockingQueue<>();
		}
	}

	public static void main(String[] args) {

		//下面三行代码模拟一个大小为3 的障栅
		ReentrantLock aLock = new ReentrantLock();
		//atomicInteger用于障栅计数
		AtomicInteger atomicInteger = new AtomicInteger(3);
		//通过condition.await()模拟障栅的await() 通过condition.signalAll()模拟障栅的释放
		Condition acCondition = aLock.newCondition();

		//新建一个线程池 来跑线程
		ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3,
				5,
				1000,
				TimeUnit.SECONDS,
				QueueFactory.getInstance());

		Runnable aRunnable = new Runnable() {
			@Override
			public void run() {
				aLock.lock();
				try {
					//如果atomicInteger==0 即所有的线程都来到了障栅点,所有线程可以继续执行了
					if(atomicInteger.decrementAndGet() == 0){
						System.out.println(Thread.currentThread().getName()+"----I am coming...");
						//通过condition.signalAll()模拟障栅的释放
						acCondition.signalAll();
					}else{
						System.out.println(Thread.currentThread().getName()+"----I am waiting...");
						//通过condition.await()模拟障栅的await()
						acCondition.await();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}finally {
					aLock.unlock();
				}
				System.out.println(Thread.currentThread().getName()+"----I am running...");
			}
		};

		poolExecutor.execute(aRunnable);
		poolExecutor.execute(aRunnable);
		poolExecutor.execute(aRunnable);

		poolExecutor.shutdown();
	}
}
pool-1-thread-1----I am waiting...
pool-1-thread-2----I am waiting...
pool-1-thread-3----I am coming...
pool-1-thread-3----I am running...
pool-1-thread-2----I am running...
pool-1-thread-1----I am running...


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值