上一篇文章解决了这个面试题:实现一个容器,提供两个方法,add和size。写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5时,线程2给出提示并结束。
采用synchronized、wait和notify相结合的方式,详见:Java高并发编程之synchronized与wait和notify结合
尽管这是挺好的解决办法,当绝对谈不上最佳,本篇文章进一步讲解更优的解决方案。
使用latch(门闩)替代wait、notify来进行通知,其好处是通信方式简单,同时也可以指定等待时间。
CountDownLatch不涉及锁定,当count的值为零的时候当前线程继续运行。
当不涉及同步,只是涉及线程通信的时候,用synchronized + wait/notify显得太重了,这是应用考虑CountDownLatch。
代码如下:
public class MyContainer3 {
private List<Integer> lists = new ArrayList<>();
public void add(Integer a) {
lists.add(a);
}
public Integer size() {
return lists.size();
}
public static void main(String[] args) {
MyContainer3 c = new MyContainer3();
CountDownLatch countDownLatch = new CountDownLatch(1);
new Thread(()->{
System.out.println("thread 1 start...");
if(c.size() != 5) {
try {
countDownLatch.await();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("thread 2 end.");
}, "t2").start();
new Thread(()->{
try {
for(int i = 0; i < 10; i++) {
c.add(i);
if(c.size() == 5) {
countDownLatch.countDown();
}
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}, "t1").start();
}
}
在上面代码中,t2线程先启动,判断容器size不为5的时候,调用countDownLatch的await,开始等待;t1线程启动后,for循环每秒往容器中添加一个元素,当容器中元素个数为5的时候,调用countDownLatch的countDown方法,此时count值减为0,t1线程继续执行,而t2线程不受影响。这个过程中,没有加锁,也没有释放锁,通信过程非常简单。