1. CountDownLatch
允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。
CountDownLatch用给定的计数初始化。
await方法阻塞,直到由于调用countDown()方法,当前计数达到零,此后所有等待线程被释放,并且任何后续的调用await立即返回。
这是一个一次性的现象 - 计数无法重置。
场景举例:等所有人离开房间后才关门
public static void main(String[] args) throws Exception {
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "离开房间。");
countDownLatch.countDown();
}, "第" + i + "个人").start();
}
countDownLatch.await();// 计数器减到0之前,主线程在此位置阻塞;
System.out.println("锁门!");
}
2. CyclicBarrier
允许一组线程全部等待彼此达到共同屏障点的同步辅助。 循环阻塞在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。
屏障被称为循环,因为它可以在等待的线程被释放之后重新使用。
CyclicBarrier支持一个可选的Runnable命令,每个屏障点运行一次,在派对中的最后一个线程到达之后,但在任何线程释放之前。
在任何一方继续进行之前,此屏障操作对更新共享状态很有用。
场景举例:集齐七龙珠召唤神龙
public class Test {
public static void main(String[] args) throws Exception {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> System.out.println("召唤神龙"));
for (int i = 0; i < 7; i++) {
final int temp = i + 1;
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t集齐第" + temp + "颗龙珠");
try {
// 从0开始计数,只要增加到7就执行cyclicBarrier中定义的线程
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
3. Semaphore
一个计数信号量。 在概念上,信号量维持一组许可证。 如果有必要,每个acquire()阻止许可证可用,然后取出。
每个release()都添加了一个许可证,潜在地释放一个阻塞获取方。 但是,没有使用实际的许可证对象;
Semaphore只保留可用数量的计数,并相应地进行操作。 信号量通常用于限制线程数,而不是访问某些(物理或逻辑)资源。
总结来说就是 在信号量上定义了两个操作:
- acquire(获取) 当一个线程调用acquire操作时,要么成功获取了信号量(信号量减1),要么一致等待下去,直到别的线程有释放信号量,或超时。
- release(释放):将信号量加1,然后唤醒等待的线程。
信号量主要有两个目的,一是用于多个共享资源的互斥作用,另一个是并发线程数的控制(高并发限流???)。
场景举例:七辆汽车抢4个车位,抢不到则等待,有车位空出来继续开抢(不排队)
public class Test {
public static void main(String[] args) throws Exception {
Semaphore semaphore = new Semaphore(4);
for (int i = 0; i < 7; i++) {
new Thread(() -> {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢到了车位");
try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}
System.out.println(Thread.currentThread().getName() + "离开了车位");
semaphore.release();
}).start();
}
}
}
思考:当信号量为1时的情况相当于加了synchronize锁的资源,同一时间只能有一个线程访问。
持续更新。。。