Java并发编程之——CyclicBarrier的使用

首先看一下官方关于CyclicBarrier的简介:

/**
 * A synchronization aid that allows a set of threads to all wait for
 * each other to reach a common barrier point.  CyclicBarriers are
 * useful in programs involving a fixed sized party of threads that
 * must occasionally wait for each other. The barrier is called
 * <em>cyclic</em> because it can be re-used after the waiting threads
 * are released.

这段话的意思是:CyclicBarrier允许一组线程相互等待达到一个公共的障碍点。CyclicBarrier对于一组线程必须相互等待的场景很有用。比如有一组线程,都要往数据库里面写入操作,只有当所有的线程都往数据库里面写入数据之后,这些线程才能继续往下执行,这时候就可以使用CyclicBarrier了。当所有的等待线程释放之后,CyclicBarrier是可重用的。


CyclicBarrier有两个构造函数:

 public CyclicBarrier(int parties, Runnable barrierAction)
 public CyclicBarrier(int parties) 
参数parties指让多少个线程或者任务等待至barrier状态;参数barrierAction为当这些线程都达到barrier状态时会执行的内容。


对于CyclicBarrier来说,最重要的是await()方法:

public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit)

第一个版本比较常用,用来挂起当前线程,直至所有线程都到达barrier状态再同时执行后续任务;
第二个版本是让这些线程等待至一定的时间,如果还有线程没有到达barrier状态就直接让到达barrier的线程执行后续任务。


有一个需求:有几个同学约好一起去食堂吃饭,各自都从各自的宿舍出发,然后到宿舍楼下集合。当所有的人都到了宿舍楼下之后,再一起从宿舍楼下出发前往食堂吃饭。

下面看代码实现:

package com.easyliu.java.demo.cyclicbarrier;

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

public class CyclicBarrierTest {
	private static final int THREAD_NUMBER = 3;
	private static CyclicBarrier sCyclicBarrier = new CyclicBarrier(
			THREAD_NUMBER, new Runnable() {

				@Override
				public void run() {
					System.out.println("大家都到达了宿舍楼下,一起出发吧。。。");
				}
			});

	public static void main(String[] args) {
		ExecutorService executorService = Executors
				.newFixedThreadPool(THREAD_NUMBER);
		for (int i = 0; i < THREAD_NUMBER; i++) {
			executorService.execute(new WalkFromDomitoryToCanteenRunnable(
					sCyclicBarrier, "同学" + i));
		}
		try {
			Thread.sleep(10000);//主线程睡眠
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("CyclicBarrier重用");
		for (int i = THREAD_NUMBER; i < THREAD_NUMBER * 2; i++) {
			executorService.execute(new WalkFromDomitoryToCanteenRunnable(
					sCyclicBarrier, "同学" + i));
		}
	}

	/**
	 * 从宿舍到食堂线程
	 * 
	 * @author LiuYi
	 *
	 */
	public static class WalkFromDomitoryToCanteenRunnable implements Runnable {
		private CyclicBarrier mCyclicBarrier;
		private String mName;

		public WalkFromDomitoryToCanteenRunnable(CyclicBarrier cyclicBarrier,
				String name) {
			this.mCyclicBarrier = cyclicBarrier;
			this.mName = name;
		}

		@Override
		public void run() {
			System.out.println(mName + "开始从宿舍出发。。。");
			try {
				Thread.sleep(1000);
				mCyclicBarrier.await();// 等待别同学
				// 前往食堂
				System.out.println(mName + "开始从宿舍楼下出发。。。");
				Thread.sleep(1000);
				System.out.println(mName + "达到食堂。。。");
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (BrokenBarrierException e) {
				e.printStackTrace();
			}
		}
	}
}



输出结果如下:

同学1开始从宿舍出发。。。
同学0开始从宿舍出发。。。
同学2开始从宿舍出发。。。
大家都到达了宿舍楼下,一起出发吧。。。
同学1开始从宿舍楼下出发。。。
同学2开始从宿舍楼下出发。。。
同学0开始从宿舍楼下出发。。。
同学0达到食堂。。。
同学1达到食堂。。。
同学2达到食堂。。。
CyclicBarrier重用
同学3开始从宿舍出发。。。
同学5开始从宿舍出发。。。
同学4开始从宿舍出发。。。
大家都到达了宿舍楼下,一起出发吧。。。
同学5开始从宿舍楼下出发。。。
同学4开始从宿舍楼下出发。。。
同学3开始从宿舍楼下出发。。。
同学4达到食堂。。。
同学3达到食堂。。。
同学5达到食堂。。。



从输出结果可以看出实现了我们想要的效果,并且实现了CyclicBarrier的重用,因为初始化CyclicBarrier的时候只设置了让三个线程等待至barrier状态,也就是当有三个同学到达了宿舍楼下之后,就一起走。剩下的三个同学一起走。


CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:
CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;
而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;
另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。


参考:http://www.cnblogs.com/dolphin0520/p/3920397.html



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值