Java Thread.join()详解(转)

 

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

 

package thread.join2;

class Sleeper extends Thread{
    private int duration;
    public Sleeper(String name,int sleepTime) {
        super(name);
        duration=sleepTime;
        start();
    }
    @Override
    public void run() {
        try {
            sleep(duration);
        } catch (InterruptedException e) {
            System.out.println(currentThread()+" was interrupted. isInterrupted():"+isInterrupted());
            return;
        }
        System.out.println(currentThread()+" was awakened");
    }
}

class Joiner extends Thread{
    private Sleeper sleeper;
    public Joiner(String name,Sleeper sleeper) {
        super(name);
        this.sleeper=sleeper;
        start();
    }

    @Override
    public void run() {
        try {
            sleeper.join();
        } catch (InterruptedException e) {
            System.out.println(currentThread()+" Interrupted.");
        }
        System.out.println(currentThread()+" join completed.");
    }

}

public class JoinTest {

    public static void main(String[] args) {
        int sleepTime=1500;
        Sleeper sleepy_sleeper=new Sleeper("sleepy_sleeper", sleepTime);
        Sleeper grumpy_sleeper=new Sleeper("grumpy_sleeper", sleepTime);

        Joiner dopey_joiner=new Joiner("dopey_joiner", sleepy_sleeper);
        Joiner doc_joiner=new Joiner("doc_joiner", grumpy_sleeper);
        grumpy_sleeper.interrupt();
    }

}

Output:

Thread[grumpy_sleeper,5,main] was interrupted. isInterrupted():false
Thread[doc_joiner,5,main] join completed.
Thread[sleepy_sleeper,5,main] was awakened
Thread[dopey_joiner,5,main] join completed.

 

 

 

 

一、使用方式。

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。

http://www.open-open.com/lib/view/open1371741636171.html

 

时间: 2024-08-19 08:27:12

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

Java Thread多线程详解及用法解析_java

最全面的java多线程用法解析,如果你对Java的多线程机制并没有深入的研究,那么本文可以帮助你更透彻地理解Java多线程的原理以及使用方法. 1.创建线程 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口.在使用Runnable接口时需要建立一个Thread实例.因此,无论是通过Thread类还是Runnable接口建立线程,都必须建立Thread类或它的子类的实例.Thread构造函数: public Thread( ); public Thread(Runnab

Java 线程池详解_java

系统启动一个线程的成本是比较高的,因为它涉及到与操作系统的交互,使用线程池的好处是提高性能,当系统中包含大量并发的线程时,会导致系统性能剧烈下降,甚至导致JVM崩溃,而线程池的最大线程数参数可以控制系统中并发线程数不超过次数. 一.Executors 工厂类用来产生线程池,该工厂类包含以下几个静态工厂方法来创建对应的线程池.创建的线程池是一个ExecutorService对象,使用该对象的submit方法或者是execute方法执行相应的Runnable或者是Callable任务.线程池本身在不

JAVA线程用法详解_java

本文配合实例较为详细的讲解了Java的线程技术,相信对于深入理解Java程序设计有一定的帮助.具体如下: 很多人在学习JAVA时都对线程都有一定的了解,而当我们开始接触Android开发时,才真真正正的发现了线程是多麽的重要,本文就把对Java线程的用法心得分享给大家,供大家参考. 首先,大家一定要分清线程和进程不是一回事,进程是什么呢?进程就如我们需要执行class文件,而线程才是真正调用CPU资源来运行的.一个class文件一般只有一个进程,但线程可以有很多个,线程的执行是一种异步的执行方式

Java 多线程实例详解(二)_java

本文承接上一篇文章<Java多线程实例详解(一)>. 四.Java多线程的阻塞状态与线程控制 上文已经提到Java阻塞的几种具体类型.下面分别看下引起Java线程阻塞的主要方法. 1.join() join -- 让一个线程等待另一个线程完成才继续执行.如A线程线程执行体中调用B线程的join()方法,则A线程被阻塞,知道B线程执行完为止,A才能得以继续执行. public class ThreadTest { public static void main(String[] args) {

Java 反射机制详解及实例代码_java

Java反射详解 本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解. 下面开始正文. [案例1]通过一个对象获得完整的包名和类名 package Reflect; /** * 通过一个对象获得完整的包名和类名 * */ class Demo{ //other codes... } class hello{ public static void main(String[] args) {

java RMI原理详解

[本文转载自java RMI原理详解] 定义 RMI(Remote Method Invocation)为远程方法调用,是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法. 这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中. Java RMI:Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口.它使客户机上运行的程序

Java并发控制机制详解_java

在一般性开发中,笔者经常看到很多同学在对待java并发开发模型中只会使用一些基础的方法.比如Volatile,synchronized.像Lock和atomic这类高级并发包很多人并不经常使用.我想大部分原因都是来之于对原理的不属性导致的.在繁忙的开发工作中,又有谁会很准确的把握和使用正确的并发模型呢? 所以最近基于这个思想,本人打算把并发控制机制这部分整理成一篇文章.既是对自己掌握知识的一个回忆,也是希望这篇讲到的类容能帮助到大部分开发者.  并行程序开发不可避免地要涉及多线程.多任务的协作和

java 多线程-锁详解及示例代码_java

自 Java 5 开始,java.util.concurrent.locks 包中包含了一些锁的实现,因此你不用去实现自己的锁了.但是你仍然需要去了解怎样使用这些锁. 一个简单的锁 让我们从 java 中的一个同步块开始: public class Counter{ private int count = 0; public int inc(){ synchronized(this){ return ++count; } } } 可以看到在 inc()方法中有一个 synchronized(th

Java实例化类详解_java

Java 中实例化类的动作,你是否还是一成不变 new 对应对象呢?     经手的项目多了,代码编写量自然会增加,渐渐的会对设计模式产生感觉.     怎样使书写出来的类实例化动作,高内聚,低耦合,又兼具一定的扩展能力呢?     本文试图从几段鲜活的代码入手,给大家呈现不一样的 Java 实例化类.     下面代码取自 com.google.zxing 源码实现: public BitMatrix encode(String contents, BarcodeFormat format,