CountDownLatch
什么是CountDownLatch呢?
有这样一个场景:一个自习室中有7个人,其中一个是班长,班长的职责就是在其他六个同学离开教室之后,把教室的门锁上。按照上面的逻辑,班长一定是最后一个走的。假设每个人是一个线程,那么怎么控制班长这个线程最后离开教室呢?
CountDownLatch就可以解决这个问题:让一些线程阻塞直到另一些线程完成一系列操作才被唤醒。
CountDownLatch中有两个主要的方法:
countDown()方法:将计数器 -1
await():当一个或多个线程调用await()方法时,调用线程会被阻塞,当计数器的值变成0时,因调用await()方法而被阻塞的线程会被唤醒,继续执行。
代码示例:
public class CountDownLatchDemo{
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName() + "\t上完自习");
countDownLatch.countDown();
},String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "\t班长离开,锁门");
}
}
运行结果:
总结:其实CountDownLatch就是在做减法
CyclicBarrier
大家应该都看过七龙珠吧!集齐七颗龙珠就可以召唤神龙。
和CountDownLatch正好相反,CyclicBarrier就是在做加法 ,计数器开始是0,加到某个值的时候就执行。
代码示例:
public class CyclicBarrier{
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("集齐了7颗龙珠,开始召唤神龙");
});
for (int i = 1; i <= 7; i++) {
final int temp = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName() + "\t 收集到第"+temp+"颗龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
运行结果:
总结:CyclicBarrier在做加法
Semaphore:信号量
信号量主要有两个作用:
-
用于互斥资源的共享使用
-
控制并发的线程数
有这样一个场景:现在有3个车位,进来了6辆车。
代码示例:
public class Sema {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "\t抢到了车位");
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName() + "\t 停留3秒之后离开");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
运行结果: