一、简介
CountDownLatch 是 java.util.concurrent 包下的一个同步辅助类,它能使一个或多个线程在其他的线程的一系列操作完成之前一直等待,初始化值为计数器大小(即线程数量)。
二、使用场景
- 同时启动多个线程;
- 多个线程操作完成之前一直等待。
注:此处“同时”只能是“大约同时”,涉及到每个线程是否可以分配到一个自由的处理器,系统是否繁忙,线程释放CPU的速度,线程的优先级等等诸多因素。
三、主要方法
await() 方法是线程阻塞,直到计数器为0,才会启动;
countDown() 方法使计数器减1。
四、实例
1、高并发实例:此处为模拟100个线程同时对一条数据进行加1操作
package com.wlm.test.concurrent;
import java.util.concurrent.CountDownLatch;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.wlm.test.award.AwardDao;
/**
* @author wengliemiao
*/
@Service
public class ConcurrentTest {
@Autowired
private AwardDao awardDao;
/**
* 线程数量
*/
public static final int THREAD_NUM = 100;
/**
* 开始时间
*/
private static long startTime = 0L;
@PostConstruct
public void init() {
try {
startTime = System.currentTimeMillis();
System.out.println("CountDownLatch started at: " + startTime);
// 初始化计数器为1
CountDownLatch countDownLatch = new CountDownLatch(1);
for (int i = 0; i < THREAD_NUM; i ++) {
new Thread(new Run(countDownLatch)).start();
}
// 启动多个线程
countDownLatch.countDown();
} catch (Exception e) {
System.out.println("Exception: " + e);
}
}
/**
* 线程类
*/
private class Run implements Runnable {
private final CountDownLatch startLatch;
public Run(CountDownLatch startLatch) {
this.startLatch = startLatch;
}
@Override
public void run() {
try {
// 线程等待
startLatch.await();
// 执行操作
awardDao.update(3);
long endTime = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + " ended at: " + endTime + ", cost: " + (endTime - startTime) + " ms.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
运行前:
运行后:
2、等待多个线程处理实例:
package com.wlm.test.concurrent;
import java.util.concurrent.CountDownLatch;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Service;
/**
* @author wengliemiao
*/
@Service
public class WaitThreadTest {
@PostConstruct
public void init() {
try {
System.out.println("******************** WaitThreadTest started at:" + System.currentTimeMillis() + " ********************");
CountDownLatch stopLatch = new CountDownLatch(3);
for (int i = 0; i < 3; i ++) {
new Thread(new Run(stopLatch)).start();
}
// 等待所有线程操作完成
stopLatch.await();
System.out.println("******************** WaitThreadTest ended at:" + System.currentTimeMillis() + " ********************");
} catch (Exception e) {
e.printStackTrace();
}
}
public class Run implements Runnable {
private CountDownLatch stopLatch;
public Run(CountDownLatch countDownLatch) {
this.stopLatch = countDownLatch;
}
@Override
public void run() {
// 线程操作
System.out.println(Thread.currentThread().getName() + " Handler...");
// 线程结束操作
stopLatch.countDown();
}
}
}
运行结果:
四、InterruptedException
如果当前线程设置了 interrupted 状态,或者在调用 await() 方法之后等待的过程中,被其他线程打断(如调用 interrupt() 方法),会抛出 InterruptedException 异常,因此最好捕捉相应的异常。