CountDownLatch类
基本概念
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
一种同步辅助工具,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成
原理及缺点
A
CountDownLatchis initialized with a given count. Theawaitmethods block until the current count reaches zero due to invocations of thecountDown()method, after which all waiting threads are released and any subsequent invocations ofawaitreturn immediately. This is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using aCyclicBarrier.CountDownLatch是用给定的计数初始化的。由于调用countDown()方法,await方法会一直阻塞,直到当前计数达到零,然后释放所有等待的线程,并立即返回任何后续的await调用。这是一种一次性现象——无法重置计数。如果需要重置计数的版本,请考虑使用
CyclicBarrier
多功能使用
A
CountDownLatchis a versatile synchronization tool and can be used for a number of purposes. ACountDownLatchinitialized with a count of one serves as a simple on/off latch, or gate: all threads invokingawaitwait at the gate until it is opened by a thread invokingcountDown(). ACountDownLatchinitialized to N can be used to make one thread wait until N threads have completed some action, or some action has been completed N times.
CountDownLatch是一种多功能同步工具,可用于多种目的。以计数1初始化的CountDownLatch用作简单的开/关闩锁或门:所有调用的线程等待等待在门上等待,直到它被调用countDown()的线程打开。初始化为N的CountDownLatch可用于制作一个线程,直到N个线程完成某些操作,或者某些操作已完成N次
经典用法1
某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为new CountDownLatch(n),每当一个任务线程执行完毕,就将计数器减1 countdownLatch.countDown(),当计数器的值变为0时,在CountDownLatch上await()的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行
经典用法2
实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的CountDownLatch(1),将其计算器初始化为1,多个线程在开始执行任务前首先countdownlatch.await(),当主线程调用countDown()时,计数器变为0,多个线程同时被唤醒
非countDown线程处理
A useful property of a
CountDownLatchis that it doesn't require that threads callingcountDownwait for the count to reach zero before proceeding, it simply prevents any thread from proceeding past anawaituntil all threads could pass.CountDownLatch的一个有用属性是它不要求调用countDown的线程在继续之前等待计数达到零,它只是阻止任何线程经过等待,直到所有线程都可以通过
构造函数及常用方法详解
| 说明 | |
|---|---|
| CountDownLatch(int count) | 构造一个CountDownLatch使用给定计数初始化的对象 |
| count | 指CountDownLatch需调用countDown()的次数,才可唤醒await()的线程,不可为负数! |
| public void await() | 使当前线程等待直到闩锁倒计时为零,除非线程被中断 |
| public boolean await(long timeout, TimeUnit unit) | 使当前线程等待直到闩锁倒计时为零,除非线程被中断,或者指定的等待时间已过 |
| public void countDown() | 递减锁存器的计数,如果计数达到零,则释放所有等待的线程 |
| public long getCount() | 返回当前计数 |
public boolean await(long timeout, TimeUnit unit)
如果当前计数为零,则此方法立即返回值true如果当前计数大于零,则当前线程出于线程调度目的而被禁用并处于休眠状态,直到发生以下三种情况之一:
- 由于
countDown()方法的调用,计数达到零- 其他一些线程中断当前线程
- 指定的等待时间已过
如果计数达到零,则该方法返回值true
如果当前线程:
- 在进入此方法时设置其中断状态;或者
- 等待时被打断
然后InterruptedException被抛出并清除当前线程的中断状态如果指定的等待时间过去,则false 返回该值。如果时间小于或等于零,则该方法根本不会等待
timeout - 最长等待时间
unit-timeout参数的时间单位
public void countDown()
如果当前计数大于零,则递减。如果新计数为零,则为线程调度目的重新启用所有等待线程
如果当前计数为零,则什么也不会发生
代码实现
package com.itheima.mycountdownlatch;
import java.util.concurrent.CountDownLatch;
public class ChileThread1 extends Thread {
private CountDownLatch countDownLatch;
public ChileThread1(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
//1.吃饺子
for (int i = 1; i <= 10; i++) {
System.out.println(getName() + "在吃第" + i + "个饺子");
}
//2.吃完说一声
//每一次countDown方法的时候,就让计数器-1
countDownLatch.countDown();
}
}
package com.itheima.mycountdownlatch;
import java.util.concurrent.CountDownLatch;
public class ChileThread2 extends Thread {
private CountDownLatch countDownLatch;
public ChileThread2(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
//1.吃饺子
for (int i = 1; i <= 15; i++) {
System.out.println(getName() + "在吃第" + i + "个饺子");
}
//2.吃完说一声
//每一次countDown方法的时候,就让计数器-1
countDownLatch.countDown();
}
}
package com.itheima.mycountdownlatch;
import java.util.concurrent.CountDownLatch;
public class MotherThread extends Thread {
private CountDownLatch countDownLatch;
public MotherThread(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
//1.等待
try {
//当计数器变成0的时候,会自动唤醒这里等待的线程。
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//2.收拾碗筷
System.out.println("妈妈在收拾碗筷");
}
}
package com.itheima.mycountdownlatch;
import java.util.concurrent.CountDownLatch;
public class MyCountDownLatchDemo {
public static void main(String[] args) {
//1.创建CountDownLatch的对象,需要传递给3个线程。
//在底层就定义了一个计数器,此时计数器的值就是2
CountDownLatch countDownLatch = new CountDownLatch(2);
//2.创建3个线程对象并开启他们。
MotherThread motherThread = new MotherThread(countDownLatch);
motherThread.start();
ChileThread1 t1 = new ChileThread1(countDownLatch);
t1.setName("小明");
ChileThread2 t2 = new ChileThread2(countDownLatch);
t2.setName("小红");
t1.start();
t2.start();
}
}