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类提供多线程支持,应用可以创建并发执行的多个线程. 应用 ...
随机推荐
- [SharePoint][SharePoint Designer 入门经典]Chapter8 XSLT数据试图和表单
本章概要: 1.不是利用XSLT web部件 2.使用XSLT web部件创建数据试图 3.使用XSLT表单web部件创建自定义表单 4.利用自定义动作执行列表表单
- POJ 1944
明天补上... 这道题的思路确实很精致.考虑到连的边肯定不会是一个环,所以至少有一个断点.于是,可以枚举这个断点.断点一确定,那么连边的走向也就确定了.用D[i]表示由i开始可以到达的最远点即可.对于 ...
- [Tailwind] Apply mobile-first Responsive Classes in Tailwind
In this lesson, we take a look at tailwind's mobile-first CSS architecture and learn how to apply st ...
- 低调、奢华、有内涵的敏捷式大数据方案:Flume+Cassandra+Presto+SpagoBI
基于FacebookPresto+Cassandra的敏捷式大数据 文件夹 1 1.1 1.1.1 1.1.2 1.2 1.2.1 1.2.2 2 2.1 2.2 2.3 2.4 2.5 2.6 3 ...
- 通达OA 小飞鱼工作流在线培训教程(一)HTML基础介绍
应一些刚接触工作流设计朋友的要求,这里开设一个系列教程,对通达OA工作流设计相关的内容做个介绍.方便解决一些日常经常出现的问题,希望对刚刚接触这部分工作的朋友能够有些帮助. 工作流设计须要多方面的知识 ...
- 通过Gulp流方式处理流程
http://www.cnblogs.com/gongcheng9990/archive/2014/11/25/4120434.html http://modernweb.com/2014/08/04 ...
- Exception in thread "main" java.lang.IllegalArgumentException: Illegal character in query at index 189......
Exception in thread "main" java.lang.IllegalArgumentException: Illegal character in query ...
- WebService CXF学习:复杂对象传递(List,Map)
转自:https://blog.csdn.net/z69183787/article/details/35988335 第一步:创建存储复杂对象的类(因为WebServices的复杂对象的传递,一定要 ...
- c:forTokens标签delims截取字符
转自:https://blog.csdn.net/love398146779/article/details/83853958 两个name要相同,在里边内容为空的时候才会全显示. <logic ...
- HTML5学习笔记(三):标识文本的语义元素
1.<time>元素:标注日期和时间 日期格式:YYYY-MM-DD,如2016-04-13: 时间格式(24小时制):HH-MM,如15:31: 最后,组合以上规则就可以制定具体的日期和 ...