1、AQS同步组件CountDownLatch详细讲解。
CountDownLatch:同步辅助类,通过它可以完成类似于阻塞当前线程的功能,换句话说,一个线程或者多个线程一直等待,直到其他线程操作完成,CountDownLatch,给定的计数器,来进行初始化,该计数器的操作是原子操作,同时,只能有一个线程去操作该计数器,调用该类的await()方法的线程会一直处于等待状态,直到其他线程调用countDown()方法,使当前计数器的值,变成0,每次调用countDown()方法时候,计数器的值会减1,当计数器值减为0时,所有调用await()方法的线程,就会继续往下执行,这种操作,只会出现一次,因为计数器的值,是不能被重置的。
2、CountDownLatch同步组件使用场景:
在某些业务场景中,程序执行 ,需要等待某个条件完成后,才能继续执行后续的操作。
典型的应用:
并行的计算,当某个处理量很大时,可以将该任务拆分成多个子任务,等待所有子任务都完成之后,父任务拿到了所有子任务的结果,进行汇总。
3、为什么并发模拟时可以使用CountDownLatch呢?
package aqs;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @auther: litingxuan
* @date: 2019/3/4 15:13
*/
public class CountDownLatchExample {
private final static int threadCount = 200;
public static void main(String[] args) {
//创建线程池
ExecutorService exec = Executors.newCachedThreadPool();
//创建闭锁的实例 threadCount 给定的线程数
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i<threadCount; i++) {
final int threadNum = i;
//每次放入一个线程
exec.execute(()->{
try {
test(threadNum);
} catch (Exception e) {
System.out.println("exception"+e);
} finally {
//200不停的减一,减到0时,执行await(),实际应用中,放在具体的条件里
countDownLatch.countDown();
}
});
}
try {
//校验值为0时,才会执行后面的语句,finish
countDownLatch.await();
System.out.println("finish");
//关闭线程池
exec.shutdown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void test(int threadNum) throws Exception {
Thread.sleep(100);
System.out.println("" +threadNum);
Thread.sleep(100);
}
}
直到countDown值减为0时,才执行await()之后的代码,实际应用中,放在具体的条件里。
4、另一种场景,比如说我启动了很多线程,去完成一个任务,但是这个任务,只想给它指定时间去执行,超过这个时间,就不再执行了。
在指定时间内,完成的情况:
package aqs;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @auther: litingxuan
* @date: 2019/3/4 15:13
*/
public class CountDownLatchExample {
private final static int threadCount = 200;
public static void main(String[] args) {
//创建线程池
ExecutorService exec = Executors.newCachedThreadPool();
//创建闭锁的实例 threadCount 给定的线程数
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i<threadCount; i++) {
final int threadNum = i;
//每次放入一个线程
exec.execute(()->{
try {
test(threadNum);
} catch (Exception e) {
System.out.println("exception"+e);
} finally {
//200不停的减一,减到0时,执行await(),实际应用中,放在具体的条件里
countDownLatch.countDown();
}
});
}
try {
// await(等待的时间,单位),超过这个时间就不再执行了 countDown 校验值为0时,才会执行后面的语句,finish
countDownLatch.await(10, TimeUnit.MILLISECONDS);
System.out.println("finish");
//关闭线程池 shutdown() 并不是第一时间,就把线程销毁掉,而是让当前已有的线程,全部执行完,之后,再把这个线程池销毁掉
exec.shutdown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void test(int threadNum) throws Exception {
Thread.sleep(100);
System.out.println("" +threadNum);
}
}
await(等待的时间,单位),超过这个时间就不再执行了 countDown 校验值为0时,才会执行后面的语句。
关闭线程池 shutdown() 并不是第一时间,就把线程销毁掉,而是让当前已有的线程,全部执行完,之后,再把这个线程池销毁掉。