`
sharong
  • 浏览: 485197 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
D1667ae2-8cfc-3b68-ac7c-5e282789fa4a
论开源
浏览量:8454
7eb53364-fe48-371c-9623-887640be0185
Spring-data-j...
浏览量:12757
社区版块
存档分类
最新评论

闭锁CountDownLatch和栅栏CyclicBarrier之异同举例

阅读更多
CountDownLatch和CyclicBarrier的主要联系和区别如下:
1.闭锁CountDownLatch做减计数,而栅栏CyclicBarrier则是加计数。
2.CountDownLatch是一次性的,CyclicBarrier可以重用。
3.CountDownLatch强调一个线程等多个线程完成某件事情。CyclicBarrier是多个线程互等,等大家都完成。
4.鉴于上面的描述,CyclicBarrier在一些场景中可以替代CountDownLatch实现类似的功能。

另外,值得一提的是,CountDownLatch和CyclicBarrier在创建和启动线程时,都没有明确提到同时启动全部线程,事实上这在技术上是不大可能,不必要,不提倡的。

先看例子一:
class SubRunnable implements Runnable {
	private CountDownLatch begin, end;
	private List<Integer> sublist;
	
	public SubRunnable(List<Integer> sublist, CountDownLatch begin,CountDownLatch end) {
		this.sublist = sublist;
		
		this.begin = begin;
		this.end = end;
	}
	
	@Override
	public void run() {
		try {
			begin.await();			
			
			if (sublist != null) {
				for (int i : sublist) {
					System.out.println("线程" + Thread.currentThread().getName() + ", i = " + i);
				}
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally{
			System.out.println(System.currentTimeMillis() + ",线程" + Thread.currentThread().getName() + ",开始执行!");
			end.countDown();
		}
	}
}

public class BatchWithCountDownLatch {
	private static final int MAX = 3;
	
	private static void list(List<Integer> list) {
		if(list == null){
			list = new ArrayList<Integer>();
		}
		
		for(int i = 0 ;i < 1000;i++){
			list.add(i);
		}
	}

	public static void main(String[] args) {
		List<Integer> list = new ArrayList<Integer>();
		list(list);
		
		//把list拆分成多个
		int mod = list.size() % MAX;
		int threadCount = mod == 0 ? list.size() / MAX : list.size() / MAX + 1;
		ExecutorService executors = Executors.newFixedThreadPool(threadCount);
		
		CountDownLatch begin = new CountDownLatch(1); 
		CountDownLatch end = new CountDownLatch(threadCount); 
				
		for(int i = 0; i< threadCount;i++){
			int subsize = (i + 1) * MAX;
			executors.execute(new SubRunnable(list.subList(i * MAX, subsize > list.size() ? list.size() : subsize),begin,end));
		}
		
		System.out.println("开始 !");
		begin.countDown();
		long startTime = System.currentTimeMillis();
		
		try {
			end.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			System.out.println("线程" + Thread.currentThread().getName() + "," + System.currentTimeMillis() + ", 所有线程已完成,开始进入下一步!");
			System.out.println("花费时间 -> " + (System.currentTimeMillis() - startTime) + " ms");
		}
		
		System.out.println("开始进入第二步操作! ");		
		
		System.out.println("end! ");
	}
}

这是根据jdk文档中的伪代码例程,编写的一个例子,我们完全可以将这个例程改为只使用一个CountDownLatch来实现之。经过测试,发现begin的引入对程序基本无用,当list是1000的数量级时,最先启动的线程仍然比最后启动的快几十毫秒左右;而不设置begin开始闭锁的程序,也是完全一样的情况。

例子二:
class SubRunnable implements Runnable {
	private CyclicBarrier cyclicBarrier;
	private List<Integer> sublist;
	
	public SubRunnable(List<Integer> sublist, CyclicBarrier cyclicBarrier) {
		this.sublist = sublist;
		this.cyclicBarrier = cyclicBarrier;
	}
	
	@Override
	public void run() {		
		try {
			System.out.println(System.currentTimeMillis() + ",线程" + Thread.currentThread().getName() + ",开始执行!");
			if(sublist != null){
				for(int i : sublist){
					System.out.println("线程" + Thread.currentThread().getName() + ", i = " + i);
				}
			}

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

public class ReplaceCountDownLatch {
	private static final int MAX = 3;
	
	private static void list(List<Integer> list) {
		if(list == null){
			list = new ArrayList<Integer>();
		}
		
		for(int i = 0 ;i < 10;i++){
			list.add(i);
		}
	}
	
	public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
		List<Integer> list = new ArrayList<Integer>();
		list(list);

		//把list拆分成多个
		int mod = list.size() % MAX;
		int threadCount = mod == 0 ? list.size() / MAX : list.size() / MAX + 1;
		ExecutorService executors = Executors.newFixedThreadPool(threadCount);

		final CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount,new Runnable() {
			@Override
			public void run() {
				//根据jdkdoc里的描述,哪个线程最后运行完,就执行下面的代码。
				System.out.println("线程" + Thread.currentThread().getName() + "," + System.currentTimeMillis() + ", 所有线程已完成,开始进入下一步!");
			}
		});
		
		for(int i = 0; i< threadCount;i++){
			int subsize = (i + 1) * MAX;
			executors.execute(new SubRunnable(list.subList(i * MAX, subsize > list.size() ? list.size() : subsize),cyclicBarrier));
		}
		
		cyclicBarrier.await();
		executors.shutdown();
		System.out.println("开始进入第二步操作! ");
		
		
		System.out.println("end! ");
	}
}

使用栅栏CyclicBarrier实现和上面闭锁CountDownLatch相同的功能。
0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics