概要

本文分三个部分对thread.join()进行分析:

1. join() 的示例和作用

2. join() 源码分析

3. 对网上其他分析 join() 的文章提出疑问

1. join() 的示例和作用

1.1 示例

// 父线程

public class parent {

public static void main(string[] args) {

// 创建child对象,此时child表示的线程处于new状态

child child = new child();

// child表示的线程转换为runnable状态

child.start();

// 等待child线程运行完再继续运行

child.join();

}

}

// 子线程

public class child extends thread {

public void run() {

// ...

}

}

上面代码展示了两个类:parent(父线程类),child(子线程类)。

parent.main()方法是程序的入口,通过child child = new child(); 新建child子线程(此时 child子线程处于new状态);

然后调用child.start()(child子线程状态转换为runnable);

再调用child.join(),此时,parent父线程会等待child子线程运行完再继续运行。

下图是我总结的 java 线程状态转换图:

1.2 join() 的作用

让父线程等待子线程结束之后才能继续运行。

我们来看看在 java 7 concurrency cookbook 中相关的描述(很清楚地说明了 join() 的作用):

waiting for the finalization of a thread

in some situations, we will have to wait for the finalization of a thread. for example, we mayhave a program that will begin initializing the resources it needs before proceeding with therest of the execution. we can run the initialization tasks as threads and wait for its finalizationbefore continuing with the rest of the program.for this purpose, we can use the join() method of the thread class. when we call thismethod using a thread object, it suspends the execution of the calling thread until the objectcalled finishes its execution.

当我们调用某个线程的这个方法时,这个方法会挂起调用线程,直到被调用线程结束执行,调用线程才会继续执行。

2. join() 源码分析

以下是 jdk 8 中 join() 的源码:

public final void join() throws interruptedexception {

join(0);

}

public final synchronized void join(long millis)

throws interruptedexception {

long base = system.currenttimemillis();

long now = 0;

if (millis < 0) {

throw new illegalargumentexception("timeout value is negative");

}

if (millis == 0) {

while (isalive()) {

wait(0);

}

} else {

while (isalive()) {

long delay = millis - now;

if (delay <= 0) {

break;

}

wait(delay);

now = system.currenttimemillis() - base;

}

}

}

public final synchronized void join(long millis, int nanos)

throws interruptedexception {

if (millis < 0) {

throw new illegalargumentexception("timeout value is negative");

}

if (nanos < 0 || nanos > 999999) {

throw new illegalargumentexception(

"nanosecond timeout value out of range");

}

if (nanos >= 500000 || (nanos != 0 && millis == 0)) {

millis++;

}

join(millis);

}

join() 一共有三个重载版本,分别是无参、一个参数、两个参数:

public final void join() throws interruptedexception;

public final synchronized void join(long millis) throws interruptedexception;

public final synchronized void join(long millis, int nanos) throws interruptedexception;

其中

(1)三个方法都被final修饰,无法被子类重写。

(2)join(long),join(long, long) 是synchronized method,同步的对象是当前线程实例。

(2)无参版本和两个参数版本最终都调用了一个参数的版本。

(3) join() 和 join(0) 是等价的,表示一直等下去;join(非0)表示等待一段时间。

从源码可以看到 join(0)调用了object.wait(0),其中object.wait(0)会一直等待,直到被notify/中断才返回。

while(isalive())是为了防止子线程伪唤醒(spurious wakeup),只要子线程没有terminated的,父线程就需要继续等下去。

(4) join() 和 sleep() 一样,可以被中断(被中断时,会抛出 interrupptedexception 异常);不同的是,join() 内部调用了 wait(),会出让锁,而 sleep() 会一直保持锁。

以本文开头的代码为例,我们分析一下代码逻辑:

调用链:parent.main() -> child.join() -> child.join(0) -> child.wait(0)(此时 parent线程会获得 child 实例作为锁,其他线程可以进入 child.join() ,但不可以进入 child.join(0), 因为child.join(0)是同步方法)。

如果 child 线程是 active,则调用 child.wait(0)(为了防止子线程 spurious wakeup, 需要将 wait(0) 放入while(isalive())循环中。

一旦 child 线程不为 active (状态为 terminated),child.notifyall()会被调用-> child.wait(0)返回 -> child.join(0)返回 -> child.join()返回 -> parent.main()继续执行, 子线程会调用this.notify(),child.wait(0)会返回到child.join(0) ,child.join(0)会返回到 child.join(), child.join() 会返回到 parent 父线程,parent 父线程就可以继续运行下去了。

3. 对网上其他分析 join() 的文章提出疑问

我觉得网上很多文章的描述有歧义,下面挑选一些描述进行分析,也欢迎大家留言一起讨论。

a. 子线程结束之后,"会唤醒主线程",父线程重新获取cpu执行权,继续运行。

这里感谢kerwinx的留言,子线程结束后,子线程的this.notifyall()会被调用,join()返回,父线程只要获取到锁和cpu,就可以继续运行下去了。

b. join() 将几个并行的线程"合并为一个单线程"执行。

我理解这个说法的意思,但是这样描述只会让读者更难理解。

在调用 join() 方法的程序中,原来的多个线程仍然多个线程,并没有发生“合并为一个单线程”。真正发生的是调用join() 的线程进入 timed_waiting 状态,等待 join() 所属线程运行结束后再继续运行。

一点感想:技术人员写作技术文章时,最好尽量避免使用过于口语化的词汇。

因为这种词汇歧义比较大,会让读者感到更加困惑或形成错误的理解。

到此这篇关于java中thread.join()的使用方法的文章就介绍到这了,更多相关java thread.join()内容请搜索萬仟网以前的文章或继续浏览下面的相关文章希望大家以后多多支持萬仟网!

希望与广大网友互动??

点此进行留言吧!

java thread join()_Java中Thread.join()的使用方法相关推荐

  1. java 文件通配符_Java中泛型通配符的使用方法示例

    本文实例讲述了Java中泛型通配符的使用方法.分享给大家供大家参考,具体如下: 一 点睛 引入通配符可以在泛型实例化时更加灵活地控制,也可以在方法中控制方法的参数. 语法如下: 泛型类名 extend ...

  2. java 类型转换方法_Java中的实用类型转换的方法

    Java中的实用类型转换的方法 1,              类型转换 JAVA中常用数据类型转换函数 虽然都能在JAVA API中找到,整理一下做个备份. string->byte Byte ...

  3. java对象数组_Java中对象数组的使用方法详解

    本文实例讲述了Java中对象数组的使用方法.分享给大家供大家参考,具体如下: 一 点睛 对象可以用数组来存放,通过下面两个步骤来实现. 1 声明以类为数据类型的数组变量,并用new分配内存空间给数组. ...

  4. java 数组赋值_java中为数组赋值的方法

    java中为数组赋值的方法 发布时间:2020-06-25 14:31:36 来源:亿速云 阅读:184 作者:Leah 这期内容当中小编将会给大家带来有关java中为数组赋值的方法,文章内容丰富且以 ...

  5. java 随机数生成实现_Java中生成随机数的实现方法总结

    搜索热词 在实际开发工作中经常需要用到随机数.如有些系统中创建用户后会给用户一个随机的初始化密码.这个密码由于是随机的,为此往往只有用户自己知道.他们获取了这个随机密码之后,需要马上去系统中更改.这就 ...

  6. java string 精度_Java 中的浮点数取精度方法

    1 packagecn.com.cxsw.utils;2 3 importjava.math.BigDecimal;4 5 /** 6 * 与小数位精度(四舍五入等)相关的一些常用工具方法.7 *8 ...

  7. java instance关键字_Java中instanceof关键字和isInstance()方法的区别是什么

    instanceof关键字和isInstance()方法都用于检查对象的类,那么它们之间有什么区别?下面本篇文章就来带大家了解一下instanceof关键字和isInstance()方法之间的区别,希 ...

  8. java split 冒号_Java中字符串split() 的使用方法,没你想的那么简单

    先看下面的方法,事先预测一下,经过split方法,按逗号进行分割为数组之后,生成的数组的长度是多少,目测很多人都觉得是8,但是结果却出乎意料.是5而不是8. private static void t ...

  9. java数组赋值_java中给数组赋值的方法

    1.数组操作中,可以使用等于(=)赋值 注意:此时新数组只是指向原数组的存储空间,并没有重新申请新的空间. 实例:public class ArrayTest{ public static void ...

最新文章

  1. 计算Python Numpy向量之间的欧氏距离
  2. 计算机专业考研数据结构比较,计算机专业考研科目:数据结构重点汇总
  3. php print div,JavaScrip实现PHP print_r的数功能(三种方法)
  4. 红外报警c语言,基于单片机的红外报警系统设计 (毕业论文).docx
  5. 怎样使计算机屏幕看着不累,电脑族的显示器如何摆最不累
  6. oracle 11G创建表空间、用户、配置监听和TNS
  7. try catch finally的理解
  8. java开发课程表_Java开发人员课程包,折扣高达86%
  9. 纯虚函数的一些问题和注意事项
  10. easyui框架的使用,定制日历控件
  11. python3中字符编码转换
  12. 基于单片机的简单温控风扇
  13. 360极速浏览器如何设置ie8兼容模式
  14. FatSecret Platform API
  15. Python练习实战股票网页数据
  16. python黑科技:让你无所遁形,附源码!
  17. 未明学院:管培生刚入职就被裁?校招的管培生真的那么高大上吗?
  18. 电脑怎么找到tomcat端口_查看tomcat端口号(怎么看tomcat的端口号)
  19. 团建游戏----啦啦队
  20. 14届蓝桥杯Python总结

热门文章

  1. js60秒倒计时防刷新
  2. python 调用vba 参数 保存表格_Jupyter Notebooks嵌入Excel并使用Python替代VBA宏
  3. iOS12系统图片heic如何在电脑上查看
  4. sql server 查询本周、本月所有天数的数据
  5. 黑客成功破解 PlayStation 4 支持运行 Linux
  6. 3月8日云栖精选夜读:《云栖精选阿里巴巴技术实战2016年刊》重磅发布
  7. BGP 同步 黑洞 peergroup rr 联邦 full-mesh
  8. 数据库-使用DataReader的简单实例(两种办法)
  9. IT 架构之学习教材 -WSSRA
  10. $router和$route的区别