顾名思义,闭锁就是一把锁关闭着所有线程,就好比一座大坝,线程到了大坝就只能蓄起来。一旦闭锁打开所有线程将汹涌倾泻,大坝被冲垮,无法再次使用。闭锁的作用就是让多线程(当然包括单线程)等待,直到准备好了再执行,比如系统初始化时等所有资源加载完了再拉起对外提供服务的线程。来看例子:
package com.wulinfeng.concurrent; import java.util.Random; import java.util.concurrent.CountDownLatch; 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() { public void run() { try { System.out.println("进入战斗线程,前门紧闭。"); startGate.await(); try { task.run(); } finally { System.out.println("需要集齐7个后门钥匙才能打开后门。"); endGate.countDown(); } } catch (InterruptedException ignored) { } } }; t.start(); } System.out.println("准备工作还在进行中..."); long start = System.nanoTime(); System.out.println("准备好了,开前门放狗!"); startGate.countDown(); System.out.println("锁住后门。"); endGate.await(); long end = System.nanoTime(); System.out.printf("战斗结束,耗时: %d 毫秒", (end - start) / 1000000); return end - start; } public static void main(String[] args) throws InterruptedException { new TestHarness().timeTasks(7, new Runnable() { @Override public void run() { // TODO Auto-generated method stub System.out.printf("进入真正的战斗线程中,获取战斗任务编号:%d ", new Random().nextInt()); } }); } }
运行结果:
准备工作还在进行中... 准备好了,开前门放狗! 锁住后门。 进入战斗线程,前门紧闭。 进入真正的战斗线程中,获取战斗任务编号:-1790677890 需要集齐7个后门钥匙才能打开后门。 进入战斗线程,前门紧闭。 进入真正的战斗线程中,获取战斗任务编号:1393178891 需要集齐7个后门钥匙才能打开后门。 进入战斗线程,前门紧闭。 进入真正的战斗线程中,获取战斗任务编号:913396975 需要集齐7个后门钥匙才能打开后门。 进入战斗线程,前门紧闭。 进入真正的战斗线程中,获取战斗任务编号:1153070025 需要集齐7个后门钥匙才能打开后门。 进入战斗线程,前门紧闭。 进入真正的战斗线程中,获取战斗任务编号:28168875 需要集齐7个后门钥匙才能打开后门。 进入战斗线程,前门紧闭。 进入真正的战斗线程中,获取战斗任务编号:621772416 需要集齐7个后门钥匙才能打开后门。 进入战斗线程,前门紧闭。 进入真正的战斗线程中,获取战斗任务编号:-1262513286 需要集齐7个后门钥匙才能打开后门。 战斗结束,耗时: 85 毫秒
这里再给出上面的Executor实现:
package com.wulinfeng.concurrent; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; public class TestHarnessExecutor { public long timeTasks(int nThreads, final Runnable task) throws InterruptedException { final CountDownLatch startGate = new CountDownLatch(1); final CountDownLatch endGate = new CountDownLatch(nThreads); Executor e = new Executor() { @Override public void execute(Runnable command) { // TODO Auto-generated method stub System.out.println("进入战斗线程,前门紧闭。"); try { startGate.await(); try { command.run(); } finally { System.out.println("需要集齐7个后门钥匙才能打开后门。"); endGate.countDown(); } } catch (InterruptedException ignored) { } } }; for (int i = 0; i < nThreads; i++) { e.execute(task); } System.out.println("准备工作还在进行中..."); long start = System.nanoTime(); System.out.println("准备好了,开前门放狗!"); startGate.countDown(); System.out.println("锁住后门。"); endGate.await(); long end = System.nanoTime(); System.out.printf("战斗结束,耗时: %d 毫秒", (end - start) / 1000000); return end - start; } public static void main(String[] args) throws InterruptedException { new TestHarness().timeTasks(7, new Runnable() { @Override public void run() { // TODO Auto-generated method stub System.out.printf("进入真正的战斗线程中,获取战斗任务编号:%d ", new Random().nextInt()); } }); } }
运行结果:
进入战斗线程,前门紧闭。 准备工作还在进行中... 准备好了,开前门放狗! 锁住后门。 进入战斗线程,前门紧闭。 进入战斗线程,前门紧闭。 进入战斗线程,前门紧闭。 进入真正的战斗线程中,获取战斗任务编号:1091767595 需要集齐7个后门钥匙才能打开后门。 进入真正的战斗线程中,获取战斗任务编号:-1699934961 需要集齐7个后门钥匙才能打开后门。 进入真正的战斗线程中,获取战斗任务编号:904106730 需要集齐7个后门钥匙才能打开后门。 进入战斗线程,前门紧闭。 进入真正的战斗线程中,获取战斗任务编号:250921605 需要集齐7个后门钥匙才能打开后门。 进入战斗线程,前门紧闭。 进入真正的战斗线程中,获取战斗任务编号:-2036908861 需要集齐7个后门钥匙才能打开后门。 进入战斗线程,前门紧闭。 进入真正的战斗线程中,获取战斗任务编号:-1446427056 需要集齐7个后门钥匙才能打开后门。 进入真正的战斗线程中,获取战斗任务编号:1985416759 需要集齐7个后门钥匙才能打开后门。 战斗结束,耗时: 103 毫秒