一、CountdownLatch
CountdownLatch非常容易理解,当我们开启多少个线程的数量的时候,我们希望这些线程里面的方法全部执行完毕之后才继续执行这些次级线程之外主线程里的剩余业务代码。用synchronized或者lock这种方法实在是太low了,我们不妨用一种比较好玩的全新API数据结构——CountdownLatch!让我们看一下它的功能具体执行情况:
package test;
import java.util.concurrent.CountDownLatch;
public class Test {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1 ; i <= 6 ; i++){
new Thread(()->{
System.out.println((Thread.currentThread().getName() + "Go out"));
countDownLatch.countDown();
},String.valueOf(i)).start();
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Close Door");
}
}
执行的结果是这样:
2Go out
5Go out
3Go out
1Go out
4Go out
6Go out
Closr Door
那么我们如果说把这个API去掉,会发生的事情结果也可想而知:
public class Test {
public static void main(String[] args) {
// CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1 ; i <= 6 ; i++){
new Thread(()->{
System.out.println((Thread.currentThread().getName() + "Go out"));
// countDownLatch.countDown();
},String.valueOf(i)).start();
}
// try {
// countDownLatch.await();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println("Close Door");
}
}
Close Door
5Go out
1Go out
6Go out
4Go out
3Go out
2Go out
所以说这里的countdownLatch的初始化添加进去的数字一把来讲就是我们要开启的线程数量,每次for循环最后的一步就是执行countDown的方法,在for循环之外紧接着添加一句await方法的使用来保证主线程处于礼让的状态。最终的结果就是理想型的!
二、CyclicBarrier
说实话这个跟上一个区别也不算太大,如果说你只是想要一个简单的阻塞逻辑用上一个就行,这一个API的强大功能在于使用这个可以让多个不同的阻塞队列对象在分线程执行到各自一定阶段之后,便可以挨个处理自己的特殊逻辑,请看:
package test;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
public class Test {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(6,()->{
System.out.println("召唤龙珠成功!");
});
for (int i = 1;i <= 7;i++){
final int temp = i;
new Thread(()-> {
System.out.println(Thread.currentThread().getName() + "收集" + temp + "个龙珠");
try {
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
).start();
}
}
}
Thread-0收集1个龙珠
Thread-2收集3个龙珠
Thread-1收集2个龙珠
Thread-5收集6个龙珠
Thread-3收集4个龙珠
Thread-6收集7个龙珠
Thread-4收集5个龙珠
召唤龙珠成功!
三、Semaphore
这个API的个性就比较强烈了,让我们想想这样的情景,你在你的小区地下停车场停车,假如一共有600个业主,却只有500个车位,所有人都有车,那么总有至多100人需要等待并且抢占,而这个API就满足这层意思!有限的队列被抢占,剩下的只能阻塞等待队列中的某一个元素被释放。
package test;
import java.util.concurrent.*;
public class Test {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 1;i <= 7;i++){
new Thread(()-> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "抢到车位");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName() + "离开车位");
} catch (Exception e) {
e.printStackTrace();
} finally {
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
1抢到车位
2抢到车位
3抢到车位
1离开车位
2离开车位
4抢到车位
5抢到车位
3离开车位
6抢到车位
4离开车位
7抢到车位
5离开车位
6离开车位
7离开车位
进程已结束,退出代码为 0
各有所长,因地制宜!
本文探讨了CountDownLatch用于线程同步确保所有子线程执行完毕,CyclicBarrier支持多个线程同步到达特定阶段,Semaphore则限制并发资源。理解它们在多线程场景中的作用和区别。

被折叠的 条评论
为什么被折叠?



