,,Java中Thread.join()的使用方法

,,Java中Thread.join()的使用方法

这篇文章主要介绍了Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)中Thread.join()的使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

概要

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

1.加入()的示例和作用

2.加入()源码分析

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

1. join() 的示例和作用

1.1 示例

//父线程

公共类父级{

公共静态void main(String[] args) {

//创建儿童对象,此时儿童表示的线程处于新的状态

Child Child=new Child();

//子级表示的线程转换为可追捕的状态

孩子。start();

//等待儿童线程运行完再继续运行

孩子。join();

}

}

//子线程

公共类子扩展线程{

公共无效运行(){

//.

}

}

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

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

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

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

下图是我总结的Java 语言(一种计算机语言,尤用于创建网站)语言(一种计算机语言,尤用于创建网站)线程状态转换图:

1.2 join() 的作用

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

我们来看看在Java 7并发食谱中相关的描述(很清楚地说明了加入()的作用):

等待线程的终结

在某些情况下,我们将不得不等待线程的终结。例如,我们可能有一个程序,它将在继续执行其余部分之前开始初始化它需要的资源。我们可以将初始化任务作为线程运行,并在继续程序的其余部分之前等待它的终结。为此,我们可以使用线类的加入()方法。当我们使用一个线程对象调用这个方法时,它会挂起调用线程的执行,直到被调用的对象完成它的执行。

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

2. join() 源码分析

以下是JDK 8中加入()的源码:

公共最终无效联接()引发中断的异常{

加入(0);

}

公共最终同步无效连接(长毫秒)

引发中断的异常{

长基=系统。当前时间毫秒();

long now=0;

如果(毫秒0) {

抛出新的IllegalArgumentException("超时值为负");

}

如果(毫秒==0) {

while (isAlive()) {

等待(0);

}

}否则{

while (isAlive()) {

长延时=毫秒-现在;

如果(延迟=0) {

打破;

}

等待(延迟);

现在=系统。当前时间millis()-base;

}

}

}

公共最终同步空连接(长毫秒,整数毫微秒)

引发中断的异常{

如果(毫秒0) {

抛出新的IllegalArgumentException("超时值为负");

}

if (nanos 0 || nanos 999999) {

抛出新的IllegalArgumentException(

纳秒超时值超出范围');

}

if (nanos=500000 || (nanos!=0毫秒==0)) {

米利斯;

}

加入(毫里斯);

}

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

公共最终无效联接()引发中断异常

公共最终同步无效连接(长毫秒)引发中断异常

公共最终同步空连接(长毫秒,整数毫微秒)抛出中断异常

其中

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

(2)加入(长),加入(长,长)是同步方法,同步的对象是当前线程实例。

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

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

从源代码可以看出,join(0)调用Object.wait(0),其中Object.wait(0)会一直等到被notify/中断。

而(isAlive())是为了防止子线程伪唤醒。只要子线程没有终止,父线程就需要继续等待。

(4) join(),和sleep()一样,可以被中断(中断时会抛出InterrupptedException异常);不同之处在于,join()在内部调用wait(),这将释放锁,而sleep()将始终保持锁。

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

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

如果子线程是活动的,则调用child.wait(0)(为了防止子线程虚假唤醒,需要将wait(0)放在while(isAlive())循环中)。

一旦子线程不活动(状态为终止),将调用child . notifyall(). wait(0)返回-child.join(0)返回-child.join()返回-Parent.main()继续执行,子线程将调用this.notify(),child.wait(0)返回child.join(0),child.join(0)返回child.join(),child.join()返回父线程,这样父线程可以继续运行。

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

我觉得网上很多文章的描述都模棱两可。下面是一些描述供分析。也欢迎大家留下评论,一起讨论。

A.子线程结束后,‘主线程会被唤醒’,父线程会重新获得cpu执行权,继续运行。

感谢kerwinX给你的留言。子线程结束后,会调用子线程的this.notifyAll(),join()会返回。只要父线程得到锁和CPU,就可以继续运行。

B.join()将几个并行线程“组合成一个线程”来执行。

我理解这种说法的含义,但这种描述只会让读者更难理解。

在调用join()方法的程序中,原来的多个线程还是多个线程,不会出现“合并成一个线程”的情况。真正发生的是调用join()的线程进入TIMED_WAITING状态,等待join()所属的线程结束后再继续运行。

一些思考:技术人员写技术文章时,最好避免使用过于口语化的词语。

因为这类词汇比较模糊,会让读者感觉更加混乱,或者形成错误的理解。

关于Java Thread.join()的使用,本文到此为止。有关Java Thread.join()的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望你以后能支持我们!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: