Java多线程之CountDownLatch

2014-11-24 02:25:29 · 作者: · 浏览: 0

为了解决多线程问题,java.util.concurrent包从Java SE5开始引入了一个新类CountDownLatch。其功能主要用来同步多个任务的执行顺序,CountDown的意思是倒数计秒,Latch做为名词有门闩和锁存器的意思。


锁存器的最主要作用是缓存,其次完成高速的控制其与慢速的外设的不同步问题,再其次是解决驱动的问题,最后是解决一个 I/O 口既能输出也能输入的问题。

因此,顾名思义,CountDownLatch可以在倒数计时期间保持多个任务的执行状态,倒计时结束时便可以解锁并唤醒其他任务。
CountDownLatch最典型的应用就是将一个大的任务分解成N个子任务,当N个子任务执行完毕后可以唤起下一个大任务。
我们将N作为倒数记时的时间来初始化一个CoutDownLatch对象,然后每当一个子任务完成时,可以将N减1,等到N为0的时候,其他正在等待的任务便可以wake up。

Package

import java.util.concurrent.*;



首先,定义一个子任务TaskPortion

private static Random rand = new Random(47);
	private final CountDownLatch latch;

	TaskPortion(CountDownLatch latch) {
		this.latch = latch;
	}

	public void run() {
		try {
			doWork();
			latch.countDown();
		} catch (InterruptedException e) {
			// Acceptable way to exit
		}
	}

	public void doWork() throws InterruptedException {
		TimeUnit.MILLISECONDS.sleep(rand.nextInt(2000));
		System.out.println(this + "completed");
	}

	public String toString() {
		return String.format("%1$-3d", id);
	}
}


然后,定义一个不同的任务,但是这个任务只有在所有子任务全部完成后才可以执行。
// Waits on the CountDownLatch
class WaitingTask implements Runnable {
	private static int counter = 0;
	private final int id = counter++;
	private final CountDownLatch latch;

	WaitingTask(CountDownLatch latch) {
		this.latch = latch;
	}

	public void run() {
		try {
			latch.await();
			System.out.println("Latch barrier passed for " + this);
		} catch (InterruptedException ex) {
			System.out.println(this + " interrupted");
		}
	}

	public String toString() {
		return String.format("WaitingTask %1$-3d ", id);
	}
}



最后,编写测试代码,通过new 100个TaskPortion来分解一个大的任务,新建10个需要等待的任务。
public class CountDownLatchDemo {
	static final int SIZE = 10;
	public static void main(String[] args) throws Exception {
		ExecutorService exec = Executors.newCachedThreadPool();
		// All must share a single CountDownLatch object:
		CountDownLatch latch = new CountDownLatch(SIZE);
		for (int i = 0; i < 10; i++) {
			exec.execute(new WaitingTask(latch));
		}
		for (int i = 0; i < SIZE; i++) {
			exec.execute(new TaskPortion(latch));
		}
		System.out.println("Launched all tasks");
		exec.shutdown(); // Quit when all tasks complete
	}
}



编译后执行,结果如下。可以看出只有当10个TaskPortion结束之后,WaitingTask才可以继续执行。
Launched all tasks
7 completed
9 completed
5 completed
8 completed
1 completed
2 completed
6 completed
4 completed
0 completed
3 completed
Latch barrier passed for WaitingTask 7
Latch barrier passed for WaitingTask 9
Latch barrier passed for WaitingTask 2
Latch barrier passed for WaitingTask 5
Latch barrier passed for WaitingTask 8
Latch barrier passed for WaitingTask 4
Latch barrier passed for WaitingTask 6
Latch barrier passed for WaitingTask 0
Latch barrier passed for WaitingTask 3
Latch barrier passed for WaitingTask 1