16. ConutDownLatch应用场景
大约 3 分钟
一、应用场景
现实生活做中有很多这样的场景:做F前需要等待A,B,C,D,E完成,A,B,C,D,E可以并发完成,没有特定顺序,例如:周末在家里吃饭,有3件事情要做,爸爸做饭,妈妈做菜,儿子收拾餐桌,摆放碗筷。可以看到这个场景的特征为:
1.在吃饭前有N件事情要做,每件事情都做完后才能吃饭,待处理的事情为N,每做完一件待处理事情就减少1,当待处理事情为0时,就可以吃饭了。
2.每件事情可以并行处理,没有先后顺序,因而提高了效率。
围绕吃饭,整个过程如下:
在应用程序中处理并行操作时和上述场景类似,碰到这种场景时可以通过java并发工具CountDownLatch来实现。
二、Show me code
代码类结构如下:
I、EatingActivity.java
class EatingActivity implements Runnable {
private CountDownLatch countDownLatch;
public EatingActivity(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
public void run() {
try {
//等待吃饭
System.out.println("Waiting for dinner...");
this.countDownLatch.await();
//所有事情做完后,await被唤醒,开始吃饭
System.out.println("Start eating...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
II、MakeRice.java
/**
* 做饭
*/
class MakeRice implements Runnable {
private CountDownLatch countDownLatch;
public MakeRice(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
public void run() {
exec();
}
/**
* 模拟做饭
*/
private void exec() {
try {
System.out.println("Start making rice...");
long millis = ((int)(1+Math.random()*(5-1+1))) * 1000;
Thread.sleep(millis);
System.out.println("Making rice is finished.");
//待处理事情减1
this.countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
III、MakeDish.java
/**
* 做菜
*/
class MakeDish implements Runnable {
private CountDownLatch countDownLatch;
public MakeDish(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
public void run() {
exec();
}
/**
* 模拟做菜
*/
private void exec() {
try {
System.out.println("Start making dish...");
long millis = ((int)(1+Math.random()*(5-1+1))) * 1000;
Thread.sleep(millis);
System.out.println("Making dish is finished.");
//待处理事情减1
this.countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
IV、CleanUpTable.java
/**
* 收拾桌子
*/
class CleanUpTable implements Runnable {
private CountDownLatch countDownLatch;
public CleanUpTable(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
public void run() {
exec();
}
/**
* 模拟收拾桌子
*/
private void exec() {
try {
System.out.println("Start making rice...");
long millis = ((int)(1+Math.random()*(5-1+1))) * 1000;
Thread.sleep(millis);
System.out.println("Cleaning up table is finished.");
//待处理事情减1
this.countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
V、CountDownLatchTest.java
/**
* @ClassName CountDownLatchTest
* @Description 验证CountDownLatch
* @Author 铿然一叶
* @Date 2019/10/7 22:32
* @Version 1.0
* javashizhan.com
**/
public class CountDownLatchTest {
public static void main(String[] args) {
//为了吃饭,有3件事情要做
CountDownLatch countDownLatch = new CountDownLatch(3);
//吃饭活动
Thread eatingActivity = new Thread(new EatingActivity(countDownLatch));
eatingActivity.start();
//做饭
Thread makeRice = new Thread(new MakeRice(countDownLatch));
//做菜
Thread makeDish = new Thread(new MakeDish(countDownLatch));
//收拾桌子
Thread cleanUpTable = new Thread(new CleanUpTable(countDownLatch));
//并行开始做事情
makeRice.start();
makeDish.start();
cleanUpTable.start();
}
}
输出日志:
Waiting for dinner...
Start making rice...
Start making rice...
Start making dish...
Cleaning up table is finished.
Making rice is finished.
Making dish is finished.
Start eating...
三、其他场景-拼团
拼团场景中,满多少人后就可以成团,用到了计数器,看起来可以用CountDownLatch来实现,实际上没有必要,因为拼团可以不是并行的,只要有计数器就可以实现。
四、总结
CountDownLatch的适用场景:
1.几件事情完成之后才能开始另外一件事情。
2.需要做的几件事情可以独立完成,并且可以并行处理。