什么是JUC?
JUC就是java.util.concurrent包,这个包俗称JUC,里面都是解决并发问题的一些东西
该包的位置位于java下面的rt.jar包下面
4大常用并发工具类:
CountDownLatch
CyclicBarrier
Semaphore
ExChanger
CountDownLatch:
CountDownLatch,俗称闭锁,作用是类似加强版的Join,是让一组线程等待其他的线程完成工作以后才执行
就比如在启动框架服务的时候,我们主线程需要在环境线程初始化完成之后才能启动,这时候我们就可以实现使用CountDownLatch来完成
/**
* 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);
}
在源码中可以看到,创建CountDownLatch时,需要传入一个int类型的参数,将决定在执行次扣减之后,等待的线程被唤醒
通过这个类图就可以知道其实CountDownLatch并没有多少东西
方法介绍:
CountDownLatch:初始化方法
await:等待方法,同时带参数的是超时重载方法
countDown:每执行一次,计数器减一,就是初始化传入的数字,也代表着一个线程完成了任务
getCount:获取当前值
toString:这个就不用说了
里面的Sync是一个内部类,外面的方法其实都是操作这个内部类的,这个内部类继承了AQS,实现的标准方法,AQS将在后面的章节写
主线程中创建CountDownLatch(3),然后主线程await阻塞,然后线程A,B,C各自完成了任务,调用了countDown,之后,每个线程调用一次计数器就会减一,初始是3,然后A线程调用后变成2,B线程调用后变成1,C线程调用后,变成0,这时就会唤醒正在await的主线程,然后主线程继续执行
说一千道一万,不如代码写几行,上代码:
休眠工具类,之后的代码都会用到
package org.dance.tools;
import java.util.concurrent.TimeUnit;
/**
* 类说明:线程休眠辅助工具类
*/
public class SleepTools {
/**
* 按秒休眠
* @param seconds 秒数
*/
public static final void second(int seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
}
}
/**
* 按毫秒数休眠
* @param seconds 毫秒数
*/
public static final void ms(int seconds) {
try {
TimeUnit.MILLISECONDS.sleep(seconds);
} catch (InterruptedException e) {
}
}
}
package org.dance.day2.util;
import org.dance.tools.SleepTools;
import java.util.concurrent.CountDownLatch;
/**
* CountDownLatch的使用,有五个线程,6个扣除点
* 扣除完成后主线程和业务线程,才能执行工作
* 扣除点一般都是大于等于需要初始化的线程的
* @author ZYGisComputer
*/
public class UseCountDownLatch {
/**
* 设置为6个扣除点
*/
static CountDownLatch countDownLatch = new CountDownLatch(6);
/**
* 初始化线程
*/
private static class InitThread implements Runnable {
@Override
public void run() {
System.out.println("thread_" + Thread.currentThread().getId() + " ready init work .....");
// 执行扣减 扣减不代表结束
countDownLatch.countDown();
for (int i = 0; i < 2; i++) {
System.out.println("thread_" + Thread.currentThread().getId() + ".....continue do its work");
}
}
}
/**
* 业务线程
*/
private static class BusiThread implements Runnable {
@Override
public void run() {
// 业务线程需要在等初始化完毕后才能执行
try {
countDownLatch.await();
for (int i = 0; i < 3; i++) {
System.out.println("BusiThread " + Thread.currentThread().getId() + " do business-----");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
// 创建单独的初始化线程
new Thread(){
@Override
public void run() {
SleepTools.ms(1);
System.out.println("thread_" + Thread.currentThread().getId() + " ready init work step 1st.....");
// 扣减一次
countDownLatch.countDown();
System.out.println("begin stop 2nd.....");
SleepTools.ms(1);
System.out.println("thread_" + Thread.currentThread().getId() + " ready init work step 2nd.....");
// 扣减一次
countDownLatch.countDown();
}
}.start();
// 启动业务线程
new Thread(new BusiThread()).start();
// 启动初始化线程
for (int i = 0; i <= 3; i++) {
new Thread(new InitThread()).start();
}
// 主线程进入等待
try {
countDownLatch.await();
System.out.println("Main do ites work.....");
} catch (InterruptedException e) {
e.printStackTrace();