这篇是使用CountDownLatch和Semaphore后的一点体会。感觉前者比后者使用起来简单很多,CountDownLatch只有await和countDown两个较为关键方法。也就是说:
1) CountDownLatch初始化之后设置的计数值在被减到0之后就不能被复原了,而Semaphore可以通过release恢复信号/许可的数量,所以CountDownLatch能解决的问题范畴要小于Semaphore。在用到了semaphore.release这种操作的代码里,我们基本是没办法用CountDownLatch替换Semaphore来解决的。CountDownLatch就如一次性的门栓之于大门,门栓被拉开之后,大门的状态只能是‘开’了,我们没有能力再把门关起来。而Semaphore更像是信号灯,我们可以根据需要给出不同的‘红’、‘绿’(release)信号,因此适用的场景可以更复杂。
所以对于LeetCode多线程练习题,只有1114题可以用CountDownLatch来完成。
2) 另外,从允许、禁止这个方向上讲,Semaphore是信号/许可数量大于0时线程可运行(semapher.acquire不阻塞),对于CoundDownLatch来说则是计数值等于0时线程可运行(countDownLatch.await不阻塞)。
用CountDownLatch完成LeetCode 1114:
public class FooByCDL {
private CountDownLatch cdl2 = new CountDownLatch(1);
private CountDownLatch cdl3 = new CountDownLatch(1);
public FooByCDL() {}
public void first(Runnable printFirst) throws InterruptedException {
printFirst.run();
cdl2.countDown();
}
public void second(Runnable printSecond) throws InterruptedException {
cdl2.await();
printSecond.run();
cdl3.countDown();
}
public void third(Runnable printThird) throws InterruptedException {
cdl3.await();
printThird.run();
}
public static void main(String[] args) {
FooByCDL foo = new FooByCDL();
new Thread(() -> {
try {
foo.third(() -> System.out.print("three"));
} catch (InterruptedException ie) { ie.printStackTrace();}
}).start();
new Thread(() -> {
try {
foo.second(() -> System.out.print("two"));
} catch (InterruptedException ie) { ie.printStackTrace();}
}).start();
new Thread(() -> {
try {
foo.first(() -> System.out.print("one"));
} catch (InterruptedException ie) { ie.printStackTrace();}
}).start();
}
}