这篇文章主要介绍了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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。