Java Thread.join()详解

一、使用方式。

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

?


1

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()的用法:

1.AThread 类

  1. BThread类
  2. 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);

    }

    然后进入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。

时间: 2024-10-08 11:54:26

Java Thread.join()详解的相关文章

【转】Java Thread.join()详解

http://www.open-open.com/lib/view/open1371741636171.html 一.使用方式. join是Thread类的一个方法,启动线程后直接调用,例如: ? 1 Thread t = new AThread(); t.start(); t.join(); 二.为什么要用join()方法 在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是

Java Thread.join()详解--父线程等待子线程结束后再结束

目录(?)[+] 阅读目录 一.使用方式. 二.为什么要用join()方法 三.join方法的作用 join 四.用实例来理解 打印结果: 打印结果: 五.从源码看join()方法 join是Thread类的一个方法,启动线程后直接调用,例如: ? 1 Thread t = new AThread(); t.start(); t.join(); 回到顶部 在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需

Java Concurrency/Threads(1)——join详解

参考自:https://www.cnblogs.com/enjiex/p/3661551.html 1. Java Thread join 方法作用: 将当前线程A变为wait,执行join操作的线程B直到B结束.如果该B线程在执行中被中断. 2. join方法的三个重载: public final void join()://此方法会把当前线程变为wait,直到执行join操作的线程结束,如果该线程在执行中被中断,则会抛出InterruptedException public final sy

Java多线程编程详解

线程的同步 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问. 由于我们可以通过 private 关键字来保证数据对象只能被方法访问,所以我们只需针对方法提出一套机制,这套机制就是 synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synch

Java线程池详解(二)

一.前言 在总结了线程池的一些原理及实现细节之后,产出了一篇文章:Java线程池详解(一),后面的(一)是在本文出现之后加上的,而本文就成了(二).因为在写完第一篇关于java线程池的文章之后,越发觉得还有太多内容需要补充,每次都是修修补补,总觉得还缺点什么.在第一篇中,我着重描述了java线程池的原理以及它的实现,主要的点在于它是如何工作的.而本文的内容将更为上层,重点在于如何应用java线程池,算是对第一篇文章的一点补充,这样对于java线程池的学习和总结稍微完整一些. 使用过java线程池

Java synchronized 关键字详解

Java synchronized 关键字详解 前置技能点 进程和线程的概念 线程创建方式 线程的状态状态转换 线程安全的概念 synchronized 关键字的几种用法 修饰非静态成员方法 synchronized public void sync(){ } 修饰静态成员方法 synchronized public static void sync(){ } 类锁代码块 synchronized (类.class){ } 对象锁代码块 synchronized (this|对象){ } syn

Java关键字synchronized详解

Java关键字synchronized详解 博客分类: Java综合 Java多线程thread互联网制造 synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程A每次运行到这个方法时,都要检查有没有其它正在用这个方法的线程B(或者C D等),有的话要等正在使用这个方法的线程B(或者C D)运行完这个方法后再运行此线程A,没有的话,直接运行 它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法: 通过在方法声明中

Thread 守护线程 Thread.setDaemon详解

java中线程分为两种类型:用户线程和守护线程.通过Thread.setDaemon(false)设置为用户线程:通过Thread.setDaemon(true)设置为守护线程.如果不设置次属性,默认为用户线程. 用户线程和守护线程的区别: 1. 主线程结束后用户线程还会继续运行,JVM存活:主线程结束后守护线程和JVM的状态又下面第2条确定. 2.如果没有用户线程,都是守护线程,那么JVM结束(随之而来的是所有的一切烟消云散,包括所有的守护线程). 补充说明: 定义:守护线程--也称“服务线程

Java路径操作详解

1.基本概念的理解 绝对路径:绝对路径就是你的主页上的文件或目录在硬盘上真正的路径,(URL和物理路径)例如: C:\xyz\test.txt 代表了test.txt文件的绝对路径.http://www.sun.com/index.htm也代表了一个 URL绝对路径. 相对路径:相对与某个基准目录的路径.包含Web的相对路径(HTML中的相对目录),例如:在 Servlet中,"/"代表Web应用的根目录.和物理路径的相对表示.例如:". /" 代表当前目录, &q