CountDownLatch
- 一个线程等待另外多个线程完成后,在继续执行,有点类似于join()方法
- CountdDwonLatch是通过计数器来实现的,初始化CountDownLatch实例时需要设置计数器的个数
- CountdDwonLatch中主要用到两个方法,调用await()方法的线程处于阻塞状态,每调用一次countDown()方法,则计数器减1,直到计数器值为0时,await()方法所阻塞的线程会继续执行
- 调用await()阻塞的线程可以不止一个,可以多个线程都调用await()进行阻塞,等满足条件时执行
实例
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import com.shawntime.enjoy.architect.concurrency.SleepUtils;
/**
* countDownLatch:
*/
public class CountDownLatchTest {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 0; i < 4; ++i) {
InitThread initThread = new InitThread("init-thread-" + i, countDownLatch);
initThread.start();
}
BusinessThread businessThread = new BusinessThread("business-thread", countDownLatch);
businessThread.start();
new Thread(() -> {
{
try {
SleepUtils.sleepBySeconds(1);
System.out.println(Thread.currentThread().getName() + " really init worker step 1...");
} finally {
countDownLatch.countDown();
}
try {
SleepUtils.sleepBySeconds(1);
System.out.println(Thread.currentThread().getName() + " really init worker step 2...");
} finally {
countDownLatch.countDown();
}
}
}, "single-thread").start();
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Main do work....");
}
/**
* 初始化线程
*/
private static class InitThread extends Thread {
private CountDownLatch countDownLatch;
public InitThread(String name, CountDownLatch countDownLatch) {
super(name);
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " waiting really init...");
int time = ThreadLocalRandom.current().nextInt(1000);
SleepUtils.sleepByMilliSeconds(time);
} finally {
countDownLatch.countDown();
}
for (int i = 0; i < 3; ++i) {
System.out.println(Thread.currentThread().getName() + " init continue working...");
}
}
}
/**
* 业务线程
*/
private static class BusinessThread extends Thread {
private CountDownLatch countDownLatch;
public BusinessThread(String name, CountDownLatch countDownLatch) {
super(name);
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 3; ++i) {
System.out.println(Thread.currentThread().getName() + " business do working...");
}
}
}
}
运行结果:
init-thread-1 waiting really init...
init-thread-0 waiting really init...
init-thread-2 waiting really init...
init-thread-3 waiting really init...
init-thread-0 init continue working...
init-thread-0 init continue working...
init-thread-0 init continue working...
init-thread-1 init continue working...
init-thread-1 init continue working...
init-thread-1 init continue working...
init-thread-2 init continue working...
init-thread-2 init continue working...
init-thread-2 init continue working...
init-thread-3 init continue working...
init-thread-3 init continue working...
init-thread-3 init continue working...
single-thread really init worker step 1...
single-thread really init worker step 2...
Main do work....
business-thread business do working...
business-thread business do working...
business-thread business do working...
结果分析
1、countDownLatch计数器个数为6,则必须等到调用了6次countDown()方法之后主线程和业务线程才会执行
2、主线程和业务线程同时调用了await()方法进行阻塞
countDownLatch()方法和join()方法的区别
- join():调用某个thread的join()方法,当前线程会被阻塞,直到thread线程结束才会继续执行,join()的原理是不断检测thread线程是否存活,如果thread一直存活则会继续等待直到thread线程结束后notifyAll()方法被调用
实例:实现数据的初始化工作,主线程需要等待线程1、2、3均初始化完成后才能继续执行
countDownLatch()方法实现
import java.util.concurrent.CountDownLatch;
import com.shawntime.enjoy.architect.concurrency.SleepUtils;
public class DataInitForCountDownLatch {
private static class InitThread extends Thread {
private CountDownLatch countDownLatch;
public InitThread(String name, CountDownLatch countDownLatch) {
super(name);
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
SleepUtils.sleepByMilliSeconds(100);
System.out.println(Thread.currentThread().getName() + "线程初始化第一步完成");
SleepUtils.sleepByMilliSeconds(100);
System.out.println(Thread.currentThread().getName() + "线程初始化第二步完成");
} finally {
countDownLatch.countDown();
}
}
}
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(3);
for (int i = 1; i < 4; ++i) {
new InitThread("thread-" + i, countDownLatch).start();
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程执行....");
}
}
输出结果:
thread-3线程初始化第一步完成
thread-1线程初始化第一步完成
thread-2线程初始化第一步完成
thread-1线程初始化第二步完成
thread-2线程初始化第二步完成
thread-3线程初始化第二步完成
主线程执行....
join()方法实现
import com.shawntime.enjoy.architect.concurrency.SleepUtils;
public class DataInitForJoin {
private static class InitThread extends Thread {
public InitThread(String name) {
super(name);
}
@Override
public void run() {
SleepUtils.sleepByMilliSeconds(100);
System.out.println(Thread.currentThread().getName() + "线程初始化第一步完成");
SleepUtils.sleepByMilliSeconds(100);
System.out.println(Thread.currentThread().getName() + "线程初始化第二步完成");
}
}
public static void main(String[] args) throws InterruptedException {
InitThread initThread1 = new InitThread("thread-1");
InitThread initThread2 = new InitThread("thread-2");
InitThread initThread3 = new InitThread("thread-3");
initThread1.start();
initThread2.start();
initThread3.start();
initThread1.join();
initThread2.join();
initThread3.join();
System.out.println("主线程继续执行....");
}
}
输出结果:
thread-2线程初始化第一步完成
thread-1线程初始化第一步完成
thread-3线程初始化第一步完成
thread-2线程初始化第二步完成
thread-1线程初始化第二步完成
thread-3线程初始化第二步完成
主线程继续执行....
如果我想在初始化第一步完成结束后主线程就可以继续执行的话,则join()方法无法实现,而countDownLatch则可以轻松的实现
import java.util.concurrent.CountDownLatch;
import com.shawntime.enjoy.architect.concurrency.SleepUtils;
public class DataInitForCountDownLatch {
private static class InitThread extends Thread {
private CountDownLatch countDownLatch;
public InitThread(String name, CountDownLatch countDownLatch) {
super(name);
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
SleepUtils.sleepByMilliSeconds(100);
System.out.println(Thread.currentThread().getName() + "线程初始化第一步完成");
} finally {
countDownLatch.countDown();
}
SleepUtils.sleepByMilliSeconds(100);
System.out.println(Thread.currentThread().getName() + "线程初始化第二步完成");
}
}
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(3);
for (int i = 1; i < 4; ++i) {
new InitThread("thread-" + i, countDownLatch).start();
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程执行....");
}
}
输出结果:
thread-1线程初始化第一步完成
thread-3线程初始化第一步完成
thread-2线程初始化第一步完成
主线程执行....
thread-1线程初始化第二步完成
thread-3线程初始化第二步完成
thread-2线程初始化第二步完成
网友评论