Java线程:CountDownLatch 与Thread 的 join()
需求:
主程序中需要等待所有子线程完成后 再继续任务
两种实现方式:
一种使用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("所有线程都结束啦");
}
}
控制台输出结果:
Java线程:CountDownLatch 与Thread 的 join()的更多相关文章
- Java线程--CountDownLatch使用
原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11867656.html Java线程--CountDownLatch使用, 代码里头有详细注释 ...
- Java线程创建形式 Thread构造详解 多线程中篇(五)
Thread作为线程的抽象,Thread的实例用于描述线程,对线程的操纵,就是对Thread实例对象的管理与控制. 创建一个线程这个问题,也就转换为如何构造一个正确的Thread对象. 构造方法列表 ...
- java ---线程wait/notify/sleep/yield/join
一.线程的状态 Java中线程中状态可分为五种:New(新建状态),Runnable(就绪状态),Running(运行状态),Blocked(阻塞状态),Dead(死亡状态). New:新建状态,当线 ...
- Java线程编程中isAlive()和join()的使用详解
一个线程如何知道另一线程已经结束?Thread类提供了回答此问题的方法. 有两种方法可以判定一个线程是否结束.第一,可以在线程中调用isAlive().这种方法由Thread定义,它的通常形式如下: ...
- Java线程状态及Thread类中的主要方法
要想实现多线程,就必须在主线程中创建新的线程对象. 不论什么线程一般具有5种状态,即创建,就绪,执行,堵塞,终止. 创建状态: 在程序中用构造方法创建了一个线程对象后,新的线程对象便处于新建状态,此时 ...
- Java线程sleep,yield,join,wait方法详解
1.sleep() 当一个线程调用sleep方法后,他就会放弃cpu,转到阻塞队列,sleep(long millis)方法是Thread类中的静态方法,millis参数设定线程睡眠的时间,毫秒为单位 ...
- java线程基础巩固---Thread API综合实战之编写ThreadService实现暴力结束线程
上篇中在最后抛出一个问题,具体问题可以查看此篇[http://www.cnblogs.com/webor2006/p/7995229.html],这里不再概述,其实要实现这个需求可以用咱们之前学习的守 ...
- java线程基础巩固---Thread中断Interrupt方法学习&采用优雅的方式结束线程生命周期
Interrupt学习: 在jdk中关于interrupt相关方法有三个,如下: 关于上面的疑问会在稍后进行阐述滴,下面看代码: 编译运行: 应该说是t线程为啥在被打断之后没有退出,还是在运行状态,这 ...
- Java线程与多线程教程
本文由 ImportNew - liken 翻译自 Journaldev. Java线程是执行某些任务的轻量级进程.Java通过Thread类提供多线程支持,应用可以创建并发执行的多个线程. 应用 ...
随机推荐
- hibernate框架总结
实体类编写规则1 实体类里面属性私有的 2 私有属性使用公开的set和get方法操作 3 要求实体类有属性作为唯一值(一般使用id值) 4 实体类属性建议不使用基本数据类型,使用基本数据类型对应的包装 ...
- 深入MNIST code测试
本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50624471 依照教程:深入MNIST ...
- MySQL多线程数据导入导出工具Mydumper
http://afei2.sinaapp.com/?p=456 今天在线上使用mysqldump将数据表从一个库导入到另外一个库,结果速度特别慢,印象中有个多线程的数据导入导出工具Mydumper,于 ...
- asp.net mvc--传值-后台->前台
后台传值到前台的方式 Model Binding # 这是public ActionResult中的最后部分 return View(listmode); json方式01 public void G ...
- BA-siemens-insight使用问题汇总
insight安装完成后不要修改windows时间 1.如果在完成软件安装及授权后,更改了系统的时间,则软件会判断您电脑的时间已经更改,软件将无法启动,所以在软件完成正确安装后,禁止修改系统时间.更改 ...
- BA-siemens-apogee自适应控制
简介 APOGEE楼控系统的控制器中,包括了由 Cybosoft开发的基于无模型自适应控制技术的自适应控制. 自适应控制是一个复杂的闭环循环控制算 法.自适应控制能自动校正参数以补偿机械的系 统/负载 ...
- android Service中多线程交互
android 的service和activity是执行在UI主线程的. 在android线程中,仅仅有主线程即UI线程有自己的默认的消息队列.子线程须要创建自己的消息队列.并把消息发给队列,并循环起 ...
- HDU-1042-N!(Java大法好 && HDU大数水题)
N! Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Total Subm ...
- 命令模式之2 Invoker Vs. Client
当程序中直接编写下达命令的语句如new Cmd1().execute()时.一般会将调用者与客户类合二为一. 在GUI程序中.下达命令的语句通常包括在底层框架中.或者说底层框架包括了调用者.这时程序猿 ...
- 使用Android Studo开发NDK之Gradle的配置(能debug C代码)
配置: 用的版本号是AS1.5(也能够尝试更高版本号). Gradle地址是distributionUrl=https\://services.gradle.org/distributions/gra ...