JUC并发工具类--CountDownLatch
简介
CountDownLatch(闭锁)是一个同步协助类,允许一个或多个线程等待,直到其他线程完成操作集。
CountDownLatch使用给定的计数值(count)初始化。await()方法会阻塞直到当前的计数值(count)由于countDown()方法的调用达到0,count为0之后所有等待的线程都会被释放,并且随后对await()方法的调用都会立即返回(阻塞被唤醒)。
常用API
构造方法
/**
* Constructs a {@code CountDownLatch} initialized with the given count.
*
* @param count the number of times {@link #countDown} must be invoked
* before threads can pass through {@link #await}
* @throws IllegalArgumentException if {@code count} is negative
*/
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
参数:count
为计数器的初始值(一般需要多少个线程执行,count就设为多少)。
await()
调用 await()方法的线程会被挂起,它会等待直到 count 值为0才继续执行。
/**
* Causes the current thread to wait until the latch has counted down to
* zero, unless the thread is {@linkplain Thread#interrupt interrupted}.
*
* <p>If the current count is zero then this method returns immediately.
*
* <p>If the current count is greater than zero then the current
* thread becomes disabled for thread scheduling purposes and lies
* dormant until one of two things happen:
* <ul>
* <li>The count reaches zero due to invocations of the
* {@link #countDown} method; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread.
* </ul>
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while waiting,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared.
*
* @throws InterruptedException if the current thread is interrupted
* while waiting
*/
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
/**
* Causes the current thread to wait until the latch has counted down to
* zero, unless the thread is {@linkplain Thread#interrupt interrupted},
* or the specified waiting time elapses.
*
* <p>If the current count is zero then this method returns immediately
* with the value {@code true}.
*
* <p>If the current count is greater than zero then the current
* thread becomes disabled for thread scheduling purposes and lies
* dormant until one of three things happen:
* <ul>
* <li>The count reaches zero due to invocations of the
* {@link #countDown} method; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread; or
* <li>The specified waiting time elapses.
* </ul>
*
* <p>If the count reaches zero then the method returns with the
* value {@code true}.
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while waiting,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared.
*
* <p>If the specified waiting time elapses then the value {@code false}
* is returned. If the time is less than or equal to zero, the method
* will not wait at all.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the {@code timeout} argument
* @return {@code true} if the count reached zero and {@code false}
* if the waiting time elapsed before the count reached zero
* @throws InterruptedException if the current thread is interrupted
* while waiting
*/
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
参数:timeout
阻塞等待时间。
参数:unit
阻塞等待时间单位。
countDown()
将 count 减1,直至为0。到0时,会唤醒所有等待的线程。
/**
* Decrements the count of the latch, releasing all waiting threads if
* the count reaches zero.
*
* <p>If the current count is greater than zero then it is decremented.
* If the new count is zero then all waiting threads are re-enabled for
* thread scheduling purposes.
*
* <p>If the current count equals zero then nothing happens.
*/
public void countDown() {
sync.releaseShared(1);
}
getCount()
获取当前计数器的值。
/**
* Returns the current count.
*
* <p>This method is typically used for debugging and testing purposes.
*
* @return the current count
*/
public long getCount() {
return sync.getCount();
}
示例代码
多任务完成后合并汇总
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
public class CountDownLatchDemo2 {
public static void main(String[] args) throws Exception {
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
final int index = i;
new Thread(() -> {
try {
Thread.sleep(1000 + ThreadLocalRandom.current().nextInt(2000));
System.out.println("任务" + index +"执行完成");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
// 主线程在阻塞,当计数器为0,就唤醒主线程往下执行
countDownLatch.await();
System.out.println("主线程:在所有任务运行完成后,进行结果汇总");
}
}
模拟实现百米赛跑
import lombok.SneakyThrows;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
// begin 代表裁判 初始为 1
private static CountDownLatch begin = new CountDownLatch(1);
// end 代表玩家 初始为 8
private static CountDownLatch end = new CountDownLatch(8);
public static void main(String[] args) throws InterruptedException {
for (int i = 1; i <= 8; i++) {
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
// 预备状态
System.out.println("参赛者"+Thread.currentThread().getName()+ "已经准备好了");
// 等待裁判吹哨
begin.await();
// 开始跑步
System.out.println("参赛者"+Thread.currentThread().getName() + "开始跑步");
Thread.sleep(3000);
// 跑步结束, 跑完了
System.out.println("参赛者"+Thread.currentThread().getName()+ "到达终点");
// 跑到终点, 计数器就减一
end.countDown();
}
}).start();
}
// 等待 5s 就开始吹哨
Thread.sleep(5000);
System.out.println("开始比赛");
// 裁判吹哨, 计数器减一
begin.countDown();
// 等待所有玩家到达终点
end.await();
System.out.println("比赛结束");
}
}
应用场景总结
- 并行任务同步
CountDownLatch可以用于协调多个并行任务的完成情况,确保所有任务都完成后再继续执行下一步操作。 - 多任务汇总
CountDownLatch可以用于统计多个线程的完成情况,以确定所有线程都已完成工作。 - 资源初始化
CountDownLatch可以用于等待资源的初始化完成,以便在资源初始化完成后开始使用。