一、使用方式。

  join是Thread类的一个方法,启动线程后直接调用,例如:

Thread t = new AThread(); t.start(); t.join();

二、为什么要用join()方法

  在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。

三、join方法的作用

  在JDk的API里对于join()方法是:

join

public final void join() throws InterruptedException Waits for this thread to die. Throws: InterruptedException  - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.

  即join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在主线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。

四、用实例来理解

  写一个简单的例子来看一下join()的用法:

class BThread extends Thread {
public BThread() {
super("[BThread] Thread");
};
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " start.");
try {
for (int i = 0; i < 5; i++) {
System.out.println(threadName + " loop at " + i);
Thread.sleep(1000);
}
System.out.println(threadName + " end.");
} catch (Exception e) {
System.out.println("Exception from " + threadName + ".run");
}
}
}
class AThread extends Thread {
BThread bt;
public AThread(BThread bt) {
super("[AThread] Thread");
this.bt = bt;
}
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " start.");
try {
bt.join();
System.out.println(threadName + " end.");
} catch (Exception e) {
System.out.println("Exception from " + threadName + ".run");
}
}
}
public class TestDemo {
public static void main(String[] args) {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " start.");
BThread bt = new BThread();
AThread at = new AThread(bt);
try {
bt.start();
Thread.sleep(2000);
at.start();
at.join();
} catch (Exception e) {
System.out.println("Exception from main");
}
System.out.println(threadName + " end!");
}
}

打印结果:

 main start.    //主线程起动,因为调用了at.join(),要等到at结束了,此线程才能向下执行。
[BThread] Thread start.
[BThread] Thread loop at 0
[BThread] Thread loop at 1
[AThread] Thread start. //线程at启动,因为调用bt.join(),等到bt结束了才向下执行。
[BThread] Thread loop at 2
[BThread] Thread loop at 3
[BThread] Thread loop at 4
[BThread] Thread end.
[AThread] Thread end. // 线程AThread在bt.join();阻塞处起动,向下继续执行的结果
main end! //线程AThread结束,此线程在at.join();阻塞处起动,向下继续执行的结果。

  修改一下代码:

 public class TestDemo {
public static void main(String[] args) {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " start.");
BThread bt = new BThread();
AThread at = new AThread(bt);
try {
bt.start();
Thread.sleep(2000);
at.start();
//at.join(); //在此处注释掉对join()的调用
} catch (Exception e) {
System.out.println("Exception from main");
}
System.out.println(threadName + " end!");
}
}

  打印结果:

main start.    // 主线程起动,因为Thread.sleep(2000),主线程没有马上结束;
[BThread] Thread start. //线程BThread起动
[BThread] Thread loop at 0
[BThread] Thread loop at 1
main end! // 在sleep两秒后主线程结束,AThread执行的bt.join();并不会影响到主线程。
[AThread] Thread start. //线程at起动,因为调用了bt.join(),等到bt结束了,此线程才向下执行。
[BThread] Thread loop at 2
[BThread] Thread loop at 3
[BThread] Thread loop at 4
[BThread] Thread end. //线程BThread结束了
[AThread] Thread end. // 线程AThread在bt.join();阻塞处起动,向下继续执行的结果

  五、从源码看join()方法

  在AThread的run方法里,执行了bt.join();,进入看一下它的JDK源码:

public final void join() throws InterruptedException {
join(0L);
}

   然后进入join(0L)方法:

public final synchronized void join(long l) throws InterruptedException{
long l1 = System.currentTimeMillis();
long l2 = 0L;
if(l < 0L)
throw new IllegalArgumentException("timeout value is negative");
if(l == 0L)
for(; isAlive(); wait(0L));
else
do
{
if(!isAlive())
break;
long l3 = l - l2;
if(l3 <= 0L)
break;
wait(l3);
l2 = System.currentTimeMillis() - l1;
} while(true);
}

   单纯从代码上看: * 如果线程被生成了,但还未被起动,isAlive()将返回false,调用它的join()方法是没有作用的。将直接继续向下执行。 * 在AThread类中的run方法中,bt.join()是判断bt的alive状态,如果bt的isAlive()方法返回false,在 bt.join(),这一点就不用阻塞了,可以继续向下进行了。从源码里看,wait方法中有参数,也就是不用唤醒谁,只是不再执行wait,向下继续执行而已。 * 在join()方法中,对于isAlive()和wait()方法的作用对象是个比较让人困惑的问题:

  isAlive()方法的签名是:public final native boolean isAlive(),也就是说isAlive()是判断当前线程的状态,也就是bt的状态。
      wait()方法在jdk文档中的解释如下:
      Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).
      The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

  在这里,当前线程指的是at。

JAVA THREAD.JOIN方法详解的更多相关文章

  1. [java] java 线程join方法详解

    join方法的作用是使所属线程对象正常执行run方法,而对当前线程无限期阻塞,直到所属线程销毁后再执行当前线程的逻辑. 一.先看普通的无join方法NoJoin.java public class N ...

  2. “全栈2019”Java多线程第七章:等待线程死亡join()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  3. C#多线程详解(一) Thread.Join()的详解

    bicabo   C#多线程详解(一) Thread.Join()的详解 什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程 ...

  4. java的sleep方法详解

    java的sleep方法详解: sleep并不是永久占有CPU,没有那个线程能永久占用CPU.它是指在自己时间片内睡眠,而不是急着交出CPU.yield()就是自己愿意立即交出时间片.因此一个线程sl ...

  5. C#多线程Thread.Join()的详解

    class TestThread { private static void FirstThreadFun() { ; i < ; i++) { Console.WriteLine(Thread ...

  6. Thread.Join()的详解

    什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?线程是程序中的一个执行流,每个线程都有自己的专有寄 ...

  7. Java并发编程--多线程中的join方法详解

    Java Thread中, join()方法主要是让调用该方法的thread在完成run方法里面的部分后, 再执行join()方法后面的代码 例如:定义一个People类,run方法是输出姓名年龄. ...

  8. Java多线程中join方法详解

    join()方法用于让当前执行线程等待join线程执行结束.其实现原理是不停的检查join线程是否存活,如果join线程存活则让当前线程永远等待. join()方法部分实现细节 while(isAli ...

  9. Java多线程——多线程方法详解

    本系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线程的深入剖 ...

随机推荐

  1. TypeScript入门-基本数据类型

    ▓▓▓▓▓▓ 大致介绍 TypeScript是由C#语言之父Anders Hejlsberg主导开发的一门编程语言,TypeScript本质上是向JavaScript语言添加了可选的静态类型和基于类的 ...

  2. PRINCE2认证

    PRINCE是PRoject IN Controlled Environment(受控环境下的项目管理)的简称. PRINCE2描述了如何以一种逻辑性的.有组织的方法,按照明确的步骤对项目进行管理.它 ...

  3. [C++]STL容器Vector的内存释放

    直接抛出两句话,说明到底应该如何释放Vector占用的内存. “vector的clear不影响capacity,你应该swap一个空的vector.” <Effective STL>中的“ ...

  4. IOS开发创建开发证书及发布App应用(二)——创建证书

    2. 创建证书 证书分为两种,一种是开发者证书,主要是用来真机调试的 另一种就是发布证书,就是用来发布应用的, 最好是两种都要下载,不然编译时候可能报错,我猜想可能苹果怕你没用真机调试 创建证书分为两 ...

  5. C++ 拷贝控制和资源管理,智能指针的简单实现

    C++ 关于拷贝控制和资源管理部分的笔记,并且介绍了部分C++ 智能指针的概念,然后实现了一个基于引用计数的智能指针.关于C++智能指针部分,后面会有专门的研究. 通常,管理类外资源的类必须定义拷贝控 ...

  6. Realm数据持久化方案的简单介绍和使用(二)

    接上篇... 4. 可空属性&默认值&忽略属性 默认情况下, 属性值可空, 如果强制要求某个属性非空, 可以使用如下方法: 遵循协议方法 + (NSArray *)requiredPr ...

  7. 4月5日--课堂笔记--JS内置对象

    JavaScript 4.5 一.    JS内置对象 1.数组Array a)创建语法1:var arr=new Array(参数); i.       没有参数:创建一个初始容量为0的数组 ii. ...

  8. [Linux] PHP程序员玩转Linux系列-Nginx中的HTTPS

    1.PHP程序员玩转Linux系列-怎么安装使用CentOS 2.PHP程序员玩转Linux系列-lnmp环境的搭建 3.PHP程序员玩转Linux系列-搭建FTP代码开发环境 4.PHP程序员玩转L ...

  9. 【模板】二分图最大权完美匹配KM算法

    hdu2255模板题 KM是什么意思,详见百度百科. 总之知道它可以求二分图最大权完美匹配就可以了,时间复杂度为O(n^3). 给张图. 二分图有了边权,求最大匹配下的最大权值. 所以该怎么做呢?对啊 ...

  10. Elasticsearch搜索之best_fields分析

    顾名思义,best_field就是获取最佳匹配的field,另个可以通过tie_breaker来控制其他field的得分,boost可以设置权重(默认都为1). 下面从宏观上来讲的简单公式: scor ...