logo头像
书院的十三先生

Java并发编程入门(十四)CountDownLatch应用场景

一、应用场景

现实生活做中有很多这样的场景:做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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* 做饭
*/
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* 做菜
*/
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* 收拾桌子
*/
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* @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();
}
}

输出日志:

1
2
3
4
5
6
7
8
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.需要做的几件事情可以独立完成,并且可以并行处理。

end.


站点: http://javashizhan.com/


微信公众号: