Java线程:CountDownLatch 与Thread 的 join()
2024-09-01 02:13:14
需求:
主程序中需要等待所有子线程完成后 再继续任务
两种实现方式:
一种使用join() 方法:当在当前线程中调用某个线程 thread 的 join() 方法时,当前线程就会阻塞,直到thread 执行完成,当前线程才可以继续往下执行。join的工作原理是,不停检查thread是否存活,如果存活则让当前线程永远wait,直到thread线程终止,线程的this.notifyAll 就会被调用。
还有一种使用CountDownLatch :创建一个计数器的 CountDownLatch ,让子线程持有这个CountDownLatch 实例,当子线程完成自己的工作后,调用countDownLatch.countDown() 方法将计数器减1。countDownLatch.await() 方法会一直阻塞直到计数器为0,主线程才会继续往下执行。
以上两种方式在一下情境下可以区分差别:假设线程工作可以分为两个阶段,主线程只需要等待子线程完成他们各自工作的第一个阶段之后就可以开始自己的工作了,而不是必须等待子线程把他们的工作全部完成之后才能开始。在这种情况下,join是没办法实现这个场景的,而CountDownLatch却可以,因为它持有一个计数器,只要计数器为0,那么主线程就可以结束阻塞往下执行。我们可以在子线程完成第一阶段工作之后就把计数器减1即可,这样子线程在完成第一阶段工作之后,主线程就可以开始工作了。
没有使用这两种方式代码:
public class Test1 {
static class HandleThread extends Thread {
private String threadName;
private List<String> list;
private int startIndex;
private int endIndex; public HandleThread(String threadName, List<String> list, int startIndex, int endIndex) {
this.threadName = threadName;
this.list = list;
this.startIndex = startIndex;
this.endIndex = endIndex;
} public void run() {
List<String> subList = list.subList(startIndex, endIndex);
System.out.println(threadName+"处理了"+subList.size()+"条!startIndex:"+startIndex+"|endIndex:"+endIndex);
} } public static void main(String[] args) {
Test test = new Test();
List<String> tmpList = new ArrayList<String>();
for (int i = 0; i < 120; i++) {
tmpList.add("test" + i);
} int length = tmpList.size();
int num = 10; //初始线程数 //启动多线程
if(num > length){
num = length;
}
int baseNum = length / num;
int remainderNum = length % num;
int end = 0;
for (int i = 0; i < num; i++) {
int start = end ;
end = start + baseNum;
if(i == (num-1)){
end = length;
}else if( i < remainderNum){
end = end + 1;
}
HandleThread thread = new HandleThread("线程[" + (i + 1) + "] ", tmpList,start , end);
thread.start();
}
System.out.println("程序结束啦");
} }
控制台输出为:
使用了Thread的join()方法后:
public class Test {
static class HandleThread extends Thread {
private String threadName;
private List<String> list;
private int startIndex;
private int endIndex; public HandleThread(String threadName, List<String> list, int startIndex, int endIndex) {
this.threadName = threadName;
this.list = list;
this.startIndex = startIndex;
this.endIndex = endIndex;
} public void run() {
List<String> subList = list.subList(startIndex, endIndex);
System.out.println(threadName+"处理了"+subList.size()+"条!startIndex:"+startIndex+"|endIndex:"+endIndex);
} } public static void main(String[] args) {
Test test = new Test();
List<String> tmpList = new ArrayList<String>();
for (int i = 0; i < 120; i++) {
tmpList.add("test" + i);
} int length = tmpList.size();
int num = 10; //初始线程数 //启动多线程
if(num > length){
num = length;
} List<HandleThread> handleThreadList = new ArrayList<>();
int baseNum = length / num;
int remainderNum = length % num;
int end = 0;
for (int i = 0; i < num; i++) {
int start = end ;
end = start + baseNum;
if(i == (num-1)){
end = length;
}else if( i < remainderNum){
end = end + 1;
}
HandleThread thread = new HandleThread("线程[" + (i + 1) + "] ", tmpList,start , end);
thread.start(); handleThreadList.add(thread);
}
for(HandleThread handleThread:handleThreadList){
try {
handleThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("所有线程都结束啦");
}
}
控制台输出:
使用CountDownLatch 方式:
public class Test {
static class HandleThread extends Thread {
private String threadName;
private List<String> list;
private int startIndex;
private int endIndex;
private CountDownLatch countDownLatch; public HandleThread(String threadName, List<String> list, int startIndex, int endIndex, CountDownLatch countDownLatch) {
this.threadName = threadName;
this.list = list;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.countDownLatch = countDownLatch;
} public void run() {
List<String> subList = list.subList(startIndex, endIndex);
System.out.println(threadName+"处理了"+subList.size()+"条!startIndex:"+startIndex+"|endIndex:"+endIndex);
countDownLatch.countDown();
} } public static void main(String[] args) {
List<String> tmpList = new ArrayList<>();
for (int i = 0; i < 120; i++) {
tmpList.add("test" + i);
} int length = tmpList.size();
int num = 10; //初始线程数 //启动多线程
if(num > length){
num = length;
} int baseNum = length / num;
int remainderNum = length % num;
int end = 0; CountDownLatch countDownLatch = new CountDownLatch(num); for (int i = 0; i < num; i++) {
int start = end ;
end = start + baseNum;
if(i == (num-1)){
end = length;
}else if( i < remainderNum){
end = end + 1;
}
HandleThread thread = new HandleThread("线程[" + (i + 1) + "] ", tmpList,start , end,countDownLatch);
thread.start();
} try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有线程都结束啦");
}
}
控制台输出结果:
最新文章
- ASP.NET Aries JSAPI 文档说明:AR.DataGrid
- Authentication of Django
- DDGSpring2016 Demos
- 深入Spring IOC源码之ResourceLoader
- NOP登录验证管理
- 关于Css选择器优先级
- clone函数
- 2016 Mac OS 10.11 CocoaPods的安装问题
- php curl request
- seajs 和spm的使用简介
- Node.js笔记4
- python tcp socket 多线程
- Kattis - Peragrams
- 201521123030 《Java程序设计》第8周学习总结
- 【 js 基础 】关于this
- nginx添加编译lua模块
- JS区分对象类型
- Linux命令基础2-ls命令
- caffe关闭建立网络的log输出
- 8.4 C++标准输入流
热门文章
- 关于错误CSC : error CS0006:未能找到元数据文件
- HDU2188(巴什博奕)
- HDU 1788
- java 线程 生产者-消费者与队列,任务间使用管道进行输入、输出 解说演示样例 --thinking java4
- 读配置文件能够保持顺序的 Java Properties 类
- Codeforces 456B Fedya and Maths 打表找规律
- display:block jquery.sort()
- svn插件失效
- electron-vue中使用iview 报错this. is readonly的解决办法
- Flask上下文管理机制