`
willsunforjava
  • 浏览: 167895 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java并发框架Executor学习——CountDownLatch和CyclicBarrier

 
阅读更多

Java SE5的java.util.concurrent引入了大量设计用来解决并发问题的新类,这些类可以帮助程序员编写更加简单和健壮的并发程序

 

CountDownLatch

它被用来同步一个或多个任务,强制它们等待由其他任务执行的一组操作完成。其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值。 

CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。 

CountDownLatch可以应用的许多实例,如文件的断点续传,将文件切割后分别下载,然后各个部分下载完成后再合并文件。

 

主要方法:

 

public void countDown()

对CountDownLatch的count做减一操作,如果count减到0,就释放所有等待的线程

 

public void await() throws InterruptedException

使当前线程阻塞,直到count减为0

 

public boolean await(long timeout, TimeUnit unit) throws InterruptedException

使当前线程阻塞,直到count减为0或阻塞时间超过timeout

 

举个例子,有三个工人在为老板干活,这个老板有一个习惯,就是当三个工人把一天的活都干完了的时候,他就来检查所有工人所干的活。记住这个条件:三个工人先全部干完活,老板才检查。所以在这里用Java代码设计两个类,Worker代表工人,Boss代表老板,具体的代码实现如下:

 

public class CountDownLatchDemo {
	public class Worker implements Runnable{
		private CountDownLatch latch;
		private String name;
		public Worker(String name,CountDownLatch latch) {
			this.name = name;
			this.latch = latch;
		}
		
		@Override
		public void run() {
			doWork();
			try {
				TimeUnit.SECONDS.sleep(new Random().nextInt(5)); 
				//完成任务,使count减1
				latch.countDown();
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println(name+": 我的工作完成了");
		}
		public void doWork(){
			System.out.println(name+":正在工作");
		}
		
	}
	
	public class Boss implements Runnable{
		private CountDownLatch latch;
		Boss(CountDownLatch latch){
			this.latch = latch;
		}
		@Override
		public void run() {
			try {
				//一直阻塞,直到Worker完成工作
				latch.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("Boss检查工作");
		}
		
	}
	
	public void test(){
		CountDownLatch latch = new CountDownLatch(3);
		ExecutorService executor = Executors.newFixedThreadPool(4);
		
		Worker worker1 = new Worker("张三",latch);
		Worker worker2 = new Worker("李斯",latch);
		Worker worker3 = new Worker("王五",latch);
		Boss boss = new Boss(latch);
		executor.execute(worker1);
		executor.execute(worker2);
		executor.execute(worker3);
		executor.execute(boss);
		executor.shutdown();
	}
	
	public static void main(String[] args) {
		new CountDownLatchDemo().test();
	}
}
 

CyclicBarrier

CyclicBarrier适用于这样的情况:你希望创建一组任务,它们并行地执行工作,然后在进行下一个步骤之前等待,直至所有任务都完成。它使得所有的并行任务都将在栅栏处(Barrier)处列队,因此可以一致地向前移动。与CountDownLatch非常相似,只是CountDownLatch只触发一次事件,而CyclicBarrier可以多次重用。因此从字面意思可以翻译为“循环的栅栏”。

 

主要方法:

 

public int await() throws InterruptedException, BrokenBarrierException

使当前线程阻塞,直到所有的并行任务都执行了一轮

 

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

使当前线程阻塞,直到所有的并行任务都执行了一轮或阻塞时间超过timeout

 

public int getNumberWaiting() 

获取正在等待栅栏动作的任务数

 

应用实例:赛马游戏。本实例中有7匹马一起跑,每匹马每跑一轮,统计一下这几匹马的比赛情况,利用打印"*"的长度表示马跑的路程。本游戏利用CyclicBarrier实现,每一匹马是一个线程任务,它们并行执行,统计赛马情况是一个栅栏动作(barrierAction)。具体代码实现如下:

 

public class CyclicBarrierDemo {
	class Horse implements Runnable{
		private int strides = 0;
		private Random random = new Random(47);
		private int id;
		private CyclicBarrier barrier;
		public Horse(int id,CyclicBarrier barrier){
			this.id = id;
			this.barrier = barrier;
		}
		
		@Override
		public void run() {
			try {
				while(!Thread.interrupted()){
					synchronized (this) {
						strides += random.nextInt(3);
					}
				}
				//通知CyclicBarrier,一个任务已经完成
				barrier.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (BrokenBarrierException e) {
				e.printStackTrace();
			}
		}
		
		//返回马跑的路程
		public String track(){
			StringBuilder sb = new StringBuilder();
			for(int i=0;i<strides;i++){
				sb.append("*");
			}
			sb.append(id);
			return sb.toString();
		}
		
		public synchronized int getStrides(){
			return strides;
		}

		@Override
		public String toString() {
			return "Horse[id=" + id + "] ";
		}
	}
	
	class HorseRace{
		private final int FINISH_LINE = 100;
		private CyclicBarrier barrier;
		private List<Horse> horses = new ArrayList<Horse>();
		private ExecutorService executor;
		public HorseRace(int nHorse){
			//7匹马没跑一轮,栅栏动作就触发
			barrier = new CyclicBarrier(nHorse, new Runnable() {
				
				@Override
				public void run() {
					StringBuilder sb = new StringBuilder();
					for(int i=0;i<FINISH_LINE;i++){
						sb.append("=");
					}
					System.out.println(sb.toString());
					
					//输出每匹马的赛况
					for(Horse h : horses){
						System.out.println(h.track());
					}
					
					//有一匹马跑到终点,游戏结束
					for(Horse h : horses){
						if(h.getStrides() >= FINISH_LINE){
							System.out.println(h+" win!");
							executor.shutdownNow();
							return;
						}
					}
					try {
						TimeUnit.MILLISECONDS.sleep(200); 
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});
			executor = Executors.newCachedThreadPool();
			for(int i=0;i<nHorse;i++){
				Horse horse = new Horse(i+1,barrier);
				horses.add(horse);
				executor.execute(horse);
			}
		}
	}
	
	public void test(){
		new HorseRace(7);
	}
	
	public static void main(String[] args) {
		new CyclicBarrierDemo().test();
	}
}
 

 

 

分享到:
评论

相关推荐

    java并发变成实战

    其次,书中会深入讲解Java提供的并发工具类,如Executor框架、ThreadLocal、CountDownLatch、CyclicBarrier、Semaphore等。Executor框架允许我们更灵活地管理和调度线程,避免过度依赖线程的创建和销毁;ThreadLocal...

    Java 并发编程实战.pdf

    - **Java并发机制**:Java提供了丰富的并发机制来支持多线程程序的编写,包括但不限于`Thread`类、`Runnable`接口、`Callable`接口以及`Executor`框架等。 - **锁机制**:Java中的锁机制主要包括synchronized关键字...

    Java并发编程从入门到精通(pdf)(附源码)

    接着,书中将深入探讨Java并发工具类,如Executor框架、Semaphore信号量、CyclicBarrier和CountDownLatch等,这些工具在实际项目中有着广泛的应用,学习它们能帮助开发者更好地控制和协调并发任务。 此外,书中的...

    JAVA并发编程实践 pdf

    Java提供了一套丰富的并发工具类,如Executor框架、Future、Callable、CountDownLatch、CyclicBarrier、Semaphore等。这些工具可以帮助开发者更好地管理和控制并发任务,提高代码的灵活性和可维护性。书中将详细讲解...

    Java并发编程的艺术1

    第八章介绍了Java并发工具类,如CountDownLatch、CyclicBarrier、Semaphore等,它们在并发控制中有着广泛的应用。 第九章深入讲解了Java线程池的实现原理和最佳实践,帮助读者理解如何有效地管理和调度线程资源。...

    Java并发编程全景图.pdf

    Java并发工具类扩展了基本的并发功能,例如CountDownLatch、CyclicBarrier、Semaphore和Phaser提供了不同场景下的同步支持。Exchanger用于两个线程之间交换数据。 12. 硬件和操作系统支持 Java并发编程的成功在很大...

    JAVA并发编程艺术pdf版

    - **java.util.concurrent** 包:提供了各种并发工具类,如Semaphore(信号量)、CyclicBarrier(循环屏障)、CountDownLatch(倒计时器)和ExecutorService(线程池)等。 - **Future和Callable**:Future接口...

    JAVA并发编程实践 EN(全)

    3. **并发工具类**:详细解析Java并发库(java.util.concurrent)中的各种工具类,如Executor框架、Semaphore、CountDownLatch、CyclicBarrier、Future和Callable接口等。这些工具能帮助开发者更高效地组织并发任务...

    java并发编程实战.zip

    **锁与并发工具类**:介绍了Java.util.concurrent包中的锁机制,如ReentrantLock、读写锁(ReentrantReadWriteLock)、Condition接口,以及Semaphore、CountDownLatch、CyclicBarrier等并发工具类的使用场景和实现...

    java并发程序设计

    6. 并发流程控制:包括CountDownLatch和CyclicBarrier。CountDownLatch允许一个或多个线程等待其他线程完成操作。CyclicBarrier则用于使一定数量的线程到达一个同步点后互相等待。 7. 定时器:提供了定时任务执行的...

    java并发编程实践(第一版)

    除了线程和同步机制,Java并发包(java.util.concurrent)还提供了一些并发工具类,例如CountDownLatch、CyclicBarrier、Semaphore等,这些工具类可以帮助开发者实现复杂的线程协调机制,简化并发程序的设计。...

    java 并发编程实战

    接着,书中会详细介绍Java提供的并发工具,如Executor框架、线程池、Future、Callable、CountDownLatch、CyclicBarrier、Semaphore等。Executor框架是Java并发编程的核心,它简化了线程的管理和调度,通过定义工作...

    Java并发编程事件 mobi kindle版

    2. **Java并发API**:详细讲解了Java并发库(java.util.concurrent)中的核心类和接口,如ExecutorService、Future、Semaphore、CountDownLatch、CyclicBarrier、ThreadPoolExecutor等,以及如何使用它们来构建高效...

    java并发编程

    Java并发编程是Java开发者必须掌握的关键技能之一,它涉及到如何在多线程环境中高效、安全地执行程序。并发编程能够充分利用多核处理器的...总的来说,Java并发编程是一门深奥的学问,需要不断学习和实践才能真正精通。

    一本经典的多线程书籍 Java并发编程 设计原则与模式 第二版 (英文原版)

    5. **原子类与并发工具类**:介绍了java.util.concurrent.atomic包中的原子类,如AtomicInteger、AtomicLong等,以及Semaphore、CountDownLatch、CyclicBarrier等并发工具类的使用场景和最佳实践。 6. **线程通信**...

    java并发书籍xxxxxxx

    8. **Executor框架**:Java 5引入的Executor框架简化了线程池的管理和线程的创建,通过ThreadPoolExecutor可以创建自定义线程池,控制并发程度。 9. **Future和Callable**:Future代表异步计算的结果,Callable接口...

    Java并发编程实践.pdf

    - **Executor框架**:是Java并发工具包中的核心组件之一,提供了强大的任务管理和执行功能,如定时任务、周期性任务等。 #### 二、Java线程安全问题及解决方案 ##### 2.1 线程安全问题分析 在多线程环境下,如果不...

    Java 并发编程实战

    Java提供了内置的Thread类和Runnable接口来创建和管理线程,同时,还可以使用Executor框架来更灵活地管理和控制线程池。 其次,锁机制是实现线程间同步的关键。Java提供了synchronized关键字以及ReentrantLock、...

Global site tag (gtag.js) - Google Analytics