论坛首页 Java企业应用论坛

Java线程学习笔记(十)CountDownLatch 和CyclicBarrier

浏览 26048 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2010-04-30  

CountDownLatch

一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
用给定的计数 初始化 CountDownLatch。由于调用了 countDown()
方法,所以在当前计数到达零之前,await
方法会一直受阻塞。之后,会释放所有等待的线程,await
的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。

 

CountDownLatch 很适合用来将一个任务分为n个独立的部分,等这些部分都完成后继续接下来的任务,CountDownLatch 只能出发一次,计数值不能被重置。

CyclicBarrier:

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

CyclicBarrier可以多次重复使用

 

下面是两个例子,一个为基于CountDownLatch 的模拟项目,一个项目可以分为多个模块,只有但这些模块都完成后才可以继续下一步的工作。

一个为基于CyclicBarrier的接力赛模拟,有四个队员,当跑完后报出最终成绩。

 

 

package com.woxiaoe.study.thread;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 模拟项目的开发,只有当每个模块都完成后,项目才完成
 * 每个模块的用时不同
 * @author 小e
 *
 * 2010-4-30 下午07:41:37
 */
class Module implements Runnable{
	private CountDownLatch latch;
	private String moduleName;
	private int time;//用时
	
	

	public Module(CountDownLatch latch, String moduleName,int time) {
		super();
		this.latch = latch;
		this.moduleName = moduleName;
		this.time = time;
	}



	@Override
	public void run() {
		try {
			work();
			latch.countDown();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	private void work() throws InterruptedException{
		TimeUnit.MILLISECONDS.sleep(time);
		System.out.println(moduleName + " 完成,耗时:" + time);
	}
}
class Controller implements Runnable{
	private CountDownLatch latch;

	public Controller(CountDownLatch latch) {
		super();
		this.latch = latch;
	}

	@Override
	public void run() {
		try {
			latch.await();
			System.out.println("所有模块都完成,任务完成");
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
}
public class Project {
	static final int SIZE = 20;
	public static void main(String[] args) {
		CountDownLatch latch = new CountDownLatch(SIZE);
		Random r = new Random();
		ExecutorService exec = Executors.newCachedThreadPool();
		Controller controller = new Controller(latch);
		exec.execute(controller);
		for(int i = 0; i < SIZE; i++){
			exec.execute(new Module(latch, "模块" + (i + 1), r.nextInt(2000)));
		}
		
		exec.shutdown();
		
	}

}

 

 Output:

模块4 完成,耗时:108 模块10 完成,耗时:123 模块7 完成,耗时:136 模块19 完成,耗时:235 模块5 完成,耗时:475 模块11 完成,耗时:653 模块1 完成,耗时:745 模块2 完成,耗时:826 模块20 完成,耗时:1030 模块16 完成,耗时:1151 模块3 完成,耗时:1204 模块15 完成,耗时:1219 模块13 完成,耗时:1274 模块17 完成,耗时:1337 模块8 完成,耗时:1366 模块6 完成,耗时:1491 模块14 完成,耗时:1739 模块18 完成,耗时:1766 模块12 完成,耗时:1883 模块9 完成,耗时:1951 所有模块都完成,任务完成

 

package com.woxiaoe.study.thread;

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

/**
 * 用java模拟4X100接力赛
 * 当结束后 报成绩,应用CyclicBarrier
 * @author 小e
 *
 * 2010-4-30 下午08:13:40
 */
class Player implements Runnable{
	private String name;
	private CyclicBarrier barrier;
	private Player next;//下一棒
	private int time;//用时
	private boolean run;//第一棒
	public Player(String name, CyclicBarrier barrier, boolean run) {
		super();
		this.name = name;
		this.barrier = barrier;
		this.run = run;
	}
	@Override
	public void run() {
		try {
			synchronized (this) {
				while(!run){//等待队员
					wait();
				}
			}
			Random r = new Random();
			TimeUnit.MILLISECONDS.sleep(r.nextInt(2000));
			next(next,11 + r.nextInt(2));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	private void next(Player next, int time) {
		System.out.println(name + " 用时:" + time + ",交接棒");
		if(next != null){
			next.setTime(this.time + time);
			synchronized (next) {
				next.setRun(true);
				next.notify();
			}
		}else{
			System.out.println("跑完,总用时:" + (this.time + time));
		}
	}
	public void setTime(int time) {
		this.time = time;
	}
	public int getTime(){
		return this.time;
	}
	public void setNext(Player next) {
		this.next = next;
	}
	public void setRun(boolean run) {
		this.run = run;
	}
	
}
public class RelayRace {
	
	public static void main(String[] args) throws InterruptedException {
		final Player[] players = new Player[4];
		ExecutorService exec = Executors.newCachedThreadPool();
		CyclicBarrier barrier = new CyclicBarrier(4, new Runnable() {
			
			@Override
			public void run() {
				System.out.println("结束,总用时:" + players[3].getTime());
			}
		});
		for(int i = 0; i < 4; i++){
			players[i] = new Player("队员" + ( i + 1), barrier, i == 0);
		}
		for(int i = 0; i < 4; i++){
			if( i < 3){
				players[i].setNext(players[i + 1]);
				exec.execute(players[i]);
			}else{
				exec.execute(players[3]);
				break;
			}
		}
		/*TimeUnit.SECONDS.sleep(3);
		 * CyclicBarrier 可以重用
		for(int i = 0; i < 4; i++){
			if( i < 3){
				players[i].setNext(players[i + 1]);
				exec.execute(players[i]);
			}else{
				exec.execute(players[3]);
				break;
			}
		}*/
	}

}
 Output:
队员1 用时:11,交接棒 队员2 用时:11,交接棒 队员3 用时:11,交接棒 队员4 用时:12,交接棒 跑完,总用时:45

 


  • src.rar (2.1 KB)
  • 下载次数: 155
   发表时间:2010-07-14   最后修改:2010-07-14
说白了

CountDownLatch: 一个或者是一部分线程 ,等待另外一部线程都完成了,再继续执行
CyclicBarrier: 所有线程互相等待完成。

我觉得楼主的CyclicBarrier的例子不太好,如果目的是讲CyclicBarrier的话,不如讲4个人一起跑,等4个人都跑到终点了,才可以去吃饭……

package com.wl.test.concurrent.cyclicbarrier;

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

/**
 * 
 * @author HardPass
 * 
 */
public class CyclicBarrierTest_RelayRace {

	public static void main(String[] args) throws InterruptedException {
		ExecutorService exec = Executors.newCachedThreadPool();		
		final CyclicBarrier barrier = new CyclicBarrier(4, new Runnable() {

			@Override
			public void run() {
				System.out.println("好了,大家可以去吃饭了……"  );
			}
		});		
		
		System.out.println("要吃饭,必须所有人都到终点,oK?");				
		System.out.println("不放弃不抛弃!");
		
		for (int i = 0; i < 4; i++) {
			exec.execute(new Runnable() {

				@Override
				public void run() {
					System.out
							.println(Thread.currentThread().getName() + ":Go");
					try {
						Thread.sleep((long) (2000 * Math.random()));
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()
							+ ":我到终点了");
					try {
						barrier.await();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (BrokenBarrierException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}

					System.out.println(Thread.currentThread().getName()
							+ ":终于可以吃饭啦!");

				}
			});

		}
		exec.shutdown();
				
	}
	
	

}



0 请登录后投票
   发表时间:2010-10-30  
CyclicBarrier你传进去根本没用啊
0 请登录后投票
   发表时间:2011-03-29  
yiyidog125 写道
CyclicBarrier你传进去根本没用啊

对啊!
既然你用了concurrent包,为什么还要调用wait()?
0 请登录后投票
   发表时间:2011-03-29  
jiefei_download 写道
yiyidog125 写道
CyclicBarrier你传进去根本没用啊

对啊!
既然你用了concurrent包,为什么还要调用wait()?

此贴还被投了“良好贴”?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics