目录(?)[+]

 

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

1
Thread t = new AThread(); t.start(); t.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()的用法:

1.AThread 类

BThread类

  1. TestDemo 类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    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!");
        }
    }

    打印结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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();阻塞处起动,向下继续执行的结果。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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!");
        }
    }

    打印结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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源码:

    1
    2
    3
    public final void join() throws InterruptedException {
        join(0L);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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的active状态,如果bt的isActive()方法返回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 Thread.join()详解

    http://www.open-open.com/lib/view/open1371741636171.html 一.使用方式. join是Thread类的一个方法,启动线程后直接调用,例如: ? 1 ...

  2. Java Thread.join()详解(转)

    (1)join方法是可以中断的(2)在线程joiner在另一个线程t上调用t.join(),线程joiner将被挂起,直到线程t结束(即t.isAlive()返回为false)才恢复 package ...

  3. Java Thread.join()详解

    一.使用方式. 二.为什么要用join()方法 三.join方法的作用 join 四.用实例来理解 打印结果: 打印结果: 五.从源码看join()方法   一.使用方式. join是Thread类的 ...

  4. Java Thread.yield详解

    这是Java中的一种线程让步方法,让Java中的线程从执行状态变成就绪状态,然后处理器再从就绪队列中挑选线程进行执行(优先级大的,被挑选的概率较大),这种转换也不确定,让或者不让都是取决与处理器,线程 ...

  5. Thread.join详解

    /** * 如果某个线程在另一个线程t上调用t.join:那么此线程将被挂起,直到目标t线程的结束才恢复即t.isAlive返回为假 * * @date:2018年6月27日 * @author:zh ...

  6. Java多线程基础详解

    基础概念进程进程是操作系统结构的基础:是一次程序的执行:是一个程序及其数据在处理机上顺序执行时所发生的活动.操作系统中,几乎所有运行中的任务对应一条进程(Process).一个程序进入内存运行,即变成 ...

  7. Java如何等待子线程执行结束

    工作中往往会遇到异步去执行某段逻辑, 然后先处理其他事情, 处理完后再把那段逻辑的处理结果进行汇总的产景, 这时候就需要使用线程了. 一个线程启动之后, 是异步的去执行需要执行的内容的, 不会影响主线 ...

  8. Java线程池主线程等待子线程执行完成

    今天讨论一个入门级的话题, 不然没东西更新对不起空间和域名~~ 工作总往往会遇到异步去执行某段逻辑, 然后先处理其他事情, 处理完后再把那段逻辑的处理结果进行汇总的产景, 这时候就需要使用线程了. 一 ...

  9. Java主线程如何等待子线程执行结束(转)

    工作中往往会遇到异步去执行某段逻辑, 然后先处理其他事情, 处理完后再把那段逻辑的处理结果进行汇总的产景, 这时候就需要使用线程了. 一个线程启动之后, 是异步的去执行需要执行的内容的, 不会影响主线 ...

随机推荐

  1. 洛谷 2831 (NOIp2016) 愤怒的小鸟——仅+1所以bfs优化

    题目:https://www.luogu.org/problemnew/show/P2831 状压dp.跑得很慢.(n^2*2^n) 注意只打一只猪的情况. #include<iostream& ...

  2. 杂项-公司:星巴克百科-un

    ylbtech-杂项-公司:星巴克百科 星巴克(Starbucks)是美国一家连锁咖啡公司的名称,1971年成立,是全球最大的咖啡连锁店,其总部坐落美国华盛顿州西雅图市.星巴克旗下零售产品包括30多款 ...

  3. 字符串转换为字典的函数eval(字符串)

    首先把多行的字符串,变成一个字符串,用'''和'''扩起来: 然后把这个字符串,赋值给b 这个时候,b根本调不出来,也用不起来: 用eval(b),来格式化字符串变成字典: 然后b就变成了一个字典:

  4. DFT的补0运算

    在实际的DFT中,如果需要增加采样的密度.这里的采样是频域的采样.可以等到更加密集的谱. 如对于信号 x = [1, 1, 1, 1]做DFT如下图: 不零后的DFT, N = 8, N= 16, N ...

  5. python‘s tenth day for me

    动态参数    *args   **kwargs   *args  动态参数,万能参数 # args 接受的就是实参对应的  所有位置参数,并将其放在元祖中. def func(*args): pri ...

  6. DRF之REST规范介绍及View请求流程分析

    编程是数据结构和算法的结合,而在Web类型的App中,我们对于数据的操作请求是通过url来承载的,本文详细介绍了REST规范和CBV请求流程. 编程是数据结构和算法的结合,小程序如简单的计算器,我们输 ...

  7. Cause: java.sql.SQLException: 无效的列索引

    今天调试代码发现“Cause: java.sql.SQLException: 无效的列索引”,查资料得出结论如下: 1.sql串的?号用''括了起来. 例如:select* from user t  ...

  8. web表单disable问题

    Web表单提交之disabled问题 例如,有如下表单 <form id="inputForm" action="shorttermrental.action&qu ...

  9. mixer音量的设置:amixer小工具的…

    1.关于alsa-utils和lib的移植我的上一篇博文中已经说明了,下面我就来说说我的混音器mixer音量控制的调节过程,网上的很多方法都是比较基本的入门没有知名具体的操作方法,在此我来谈谈我的设置 ...

  10. Spring整合Junit4进行单元测试

    一. 添加依赖包(maven) <dependency> <groupId>junit</groupId> <artifactId>junit</ ...