Java 并发编程之闭锁
1. 什么是闭锁
闭锁是一种同步工具类,可以延迟线程的进度直到其到达终止状态。
2. 闭锁的作用
闭锁相当于一扇门,在闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程通过,当到达结束状态时,这扇门会打开并允许所有线程通过。
简单说,就是确保多线程或单线程的工作完成后,才能执行之后的操作。
3. Java 的闭锁实现 CountDownLatch
它可以使一个或多个状态等待一组事件发生。闭锁状态包括一个计数器,该计数器被初始化为一个正整数,表示需要等待的事件数量。 countDown方法用来递减计数器,表示有一个事件已经发生了, await方法会阻塞的一直等待计数器达到0,或者等待中的线程中断或者等待超时。
4. 实际应用
4.1 在计时测试中使用
在这里TestHarness创建一定数量线程,执行并发任务。使用两个闭锁,起始门,和结束门。起始门确保所有线程启动, 结束们确保所有线程执行完成。
public class TestHarness {
public long timeTasks(int nThreads, final Runnable task) throws InterruptedException {
final CountDownLatch startGate = new CountDownLatch(1);
final CountDownLatch endGate = new CountDownLatch(nThreads);
for (int i = 0; i < nThreads; i++) {
Thread t = new Thread() {
@Override
public void run() {
try {
startGate.await();
try {
task.run();
} finally {
endGate.countDown();
}
} catch (InterruptedException e) {
}
}
};
t.start();
}
long start = System.nanoTime();
startGate.countDown();
endGate.await();
long end = System.nanoTime();
return end - start;
}
}
4.2 模拟Shell脚本打包合并项目
我们可能有多个项目A,B,C 需要打包安装,等全部完成后才能打包合并的项目merge-all, 这时,A,B,C 可以多线程自行打包,都完成后再打包merge-all, 以下是SHELL 脚本实现,可以简单理解为 & 为开启线程, wait为闭锁门。
function package(){
cd $sourceCodePath_A
mvn clean install -Pagg &
cd $sourceCodePath_B
mvn clean install -Pagg &
cd $sourceCodePath_C
mvn clean install -Pagg &
wait
cd $sourceCodePath_all
mvn clean package -P"$env"
}
用java模拟就是如下:
public class PackageLatchTest {
private static final CountDownLatch gate = new CountDownLatch(3);
public static void packageA() {
System.out.println("compile and package A");
}
public static void packageB() {
System.out.println("compile and packge B");
}
public static void packageC() {
System.out.println("compile and package C");
}
public static void mergeAll() {
System.out.println("merge A B C !");
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
packageA();
gate.countDown();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
packageB();
gate.countDown();
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
packageC();
gate.countDown();
}
});
t1.start();
t2.start();
t3.start();
gate.await();
mergeAll();
}
}
4.3 三人到餐厅一起吃饭
这个问题就是三个人相当于3个线程,各自到达指定的餐厅,然后人到齐,开始吃饭。
具体实现 请看这个:Java 并发专题 :闭锁 CountDownLatch 之一家人一起吃个饭
5. 总结
闭锁就可简单理解为, 某项任务 可多线程执行,但是汇总需要都执行完成, 在这个地方加一个闭锁,全部完成后在执行汇总.
参考
1. Java 并发编程实战 5.5.1 闭锁
2. Java 并发专题 :闭锁 CountDownLatch 之一家人一起吃个饭 http://blog.csdn.net/lmj623565791/article/details/26626391