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类提供多线程支持,应用可以创建并发执行的多个线程. 应用 ...
随机推荐
- 2、链接数据库+mongodb基础命令行+小demo
链接数据库并且打印出数据的流程:1.在CMD里面输入 mongod 2.在CMD里面输入 mongo 3.在输入mongodb命令行里面进行操作,首先输入 show dbs 来查看是否能够链接得上库4 ...
- Emgu cv人脸检测识别
Emgu cv人脸检测识别 1.开发平台:WIN10 X64 VS2012 Emgucv版本:3.1 2.先给大家分享一个官网给的示例源代码: https://ncu.dl.sourcef ...
- redis 参数配置总结
redis.conf 配置项说明如下 1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 daemonize no 2. 当Redis以守护进程方式运行时, ...
- (0)资料官网【从零开始学Spring Boot】
Spring Boot官网:http://projects.spring.io/spring-boot/ Eclipse官网:http://www.eclipse.org/ Maven官网:http: ...
- C++ decltype类型说明符
本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50865552 1 基本语法 declt ...
- easy-ui采坑事件
新用户首次登陆修改密码 imput标签中使用easyui自带的class="easyui-passwordbox"可以是密码隐藏变成黑点但是无法禁用输入法,然后果断的加了一个typ ...
- Ural 1152 False Mirrors(状压DP)
题目地址:space=1&num=1152">Ural 1152 初学状压DP,原来状压仅仅是用到了个位运算.. 非常水的状压DP.注意四则运算的优先级是高于位运算的..也就是 ...
- Linux 下安装 jdk-7u79-linux-x64.gz,jdk1.7.0_79,jdk1.7步骤:
1.首先下载对应CentOS版本的jdk:这里我下载的是jdk-7u79-linux-x64.tar.gz 2.上传到CentOS下的目录中 3.新建一个APP目录作为存储jdk的目录 4.解压jdk ...
- BI中事实表与维度表的定义
一个典型的例子是,把逻辑业务比作一个立方体,产品维.时间维.地点维分别作为不同的坐标轴,而坐标轴的交点就是一个具体的事实.也就是说事实表是多个维度表的一个交点.而维度表是分析事实的一个窗口. 首先介绍 ...
- 关于在bootstrap的tab栏中渲染echats图表,切换tab时echats不显示问题
在开发过程中遇到这样个问题: 利用bootstrap中的tab栏,每当点击tab栏的导航时,echats仅仅只渲染第一个tab的内容,切换tab时,echats图表不显示. 其html代码为: < ...