主要的例子,参考自博客:http://blog.csdn.net/lmj623565791/article/details/26626391。
先看一个问题:
每天起早贪黑的上班,父母每天也要上班,话说今天定了个饭店,一家人一起吃个饭,通知大家下班去饭店集合。假设:3个人在不同的地方上班,必须等到3个人到场才能吃饭,用
程序如何实现呢?
不正确的实现1.
package com.zhy.concurrency.latch;
public class Test1
{
/**
* 模拟爸爸去饭店
*/
public static void fatherToRes()
{
System.out.println("爸爸步行去饭店需要3小时。");
}
/**
* 模拟我去饭店
*/
public static void motherToRes()
{
System.out.println("妈妈挤公交去饭店需要2小时。");
}
/**
* 模拟妈妈去饭店
*/
public static void meToRes()
{
System.out.println("我乘地铁去饭店需要1小时。");
}
/**
* 模拟一家人到齐了
*/
public static void togetherToEat()
{
System.out.println("一家人到齐了,开始吃饭");
}
public static void main(String[] args)
{
fatherToRes();
motherToRes();
meToRes();
togetherToEat();
}
}
输出结果:
爸爸步行去饭店需要3小时。
妈妈挤公交去饭店需要2小时。
我乘地铁去饭店需要1小时。
一家人到齐了,开始吃饭
所有人的到达应该并行的而不是穿行的,所以需要并发。
不正确的实现2:
public static void main(String[] args)
{
new Thread()
{
public void run()
{
fatherToRes();
};
}.start();
new Thread()
{
public void run()
{
motherToRes();
};
}.start();
new Thread()
{
public void run()
{
meToRes();
};
}.start();
togetherToEat();
}
输出结果:
一家人到齐了,开始吃饭
我乘地铁去饭店需要1小时。
妈妈挤公交去饭店需要2小时。
爸爸步行去饭店需要3小时。
开始吃饭一定要等到所有人到达才行。
正确的实现1.
private static volatile int i = 3;
public static void main(String[] args)
{
new Thread()
{
public void run()
{
fatherToRes();
i--;
};
}.start();
new Thread()
{
public void run()
{
motherToRes();
i--;
};
}.start();
new Thread()
{
public void run()
{
meToRes();
i--;
};
}.start();
while (i != 0);
togetherToEat();
}
这样做对CPU的负荷大。
正确的实现2:
public class demo {
public static CountDownLatch latch = new CountDownLatch(3);
public static void fatherGoRes(){
System.out.println("父亲到需要三个小时");
}
public static void motherGoRes(){
System.out.println("母亲到达需要2个小时");
}
public static void sonGoRes(){
System.out.println("儿子到达需要1个小时");
}
public static void togetherToEat(){
System.out.println("人都到期了,准备吃饭。");
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated meth奥od stub
new Thread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
fatherGoRes();
//递减锁存器的计数,如果计数到达零,则释放所有等待的线程
latch.countDown();
}
}).start();
new Thread(new Runnable() {
public void run() {
motherGoRes();
latch.countDown();
}
}).start();
new Thread(new Runnable() {
public void run() {
sonGoRes();
//递减锁存器的计数,如果计数到达零,则释放所有等待的线程
latch.countDown();
}
}).start();
//使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断
try {
latch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
togetherToEat();
}
}
所以什么是闭锁呢?
《Java 并发编程实践》中解释道:闭锁的作用类似于一扇门:在闭锁到达结束状态之前,这扇门一直是关闭着的,不允许任何线程通过,当到达结束状态时,这扇门会打开并允许所有的线程通过。且当门打开了,就永远保持打开状态。
他的使用场景:
1.确保某个计算在其需要的所有资源都被初始化之后才继续执行
2.确保某个服务再其依赖的所有其他服务都已经启动后才启动。
3.等待某个操作的所有参入这都要就绪在继续执行。
CountDownLatch的主要方法如下:
void await()
使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
boolean await(long timeout, TimeUnit unit)
使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。
void countDown()
递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
long getCount()
返回当前计数。
String toString()
返回标识此锁存器及其状态的字符串。