Thread.join()方法解析

API:

join

public final void join()
                throws InterruptedException
等待该线程终止。

抛出:
InterruptedException - 如果任何线程中断了当前线程。当抛出该异常时,当前线程的中断状态 被清除。

join

public final void join(long millis)
                throws InterruptedException
等待该线程终止的时间最长为 millis 毫秒。超时为 0 意味着要一直等下去。

参数:
millis - 以毫秒为单位的等待时间。
抛出:
InterruptedException - 如果任何线程中断了当前线程。当抛出该异常时,当前线程的中断状态 被清除。

join

public final void join(long millis,
                       int nanos)
                throws InterruptedException
等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。

参数:
millis - 以毫秒为单位的等待时间。
nanos - 要等待的 0-999999 附加纳秒。
抛出:
IllegalArgumentException - 如果 millis 值为负,则 nanos 的值不在 0-999999 范围内。
InterruptedException - 如果任何线程中断了当前线程。当抛出该异常时,当前线程的中断状态 被清除。

解析

Thread.join(),是用来指定当前主线程等待其他线程执行完毕后,再来继续执行Thread.join()后面的代码。

例1:

package com.example;

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class DataSourcesLoader implements Runnable{

	@Override
	public void run() {
		System.out.printf("Beginning data sources loading: %s\n",new Date());
	    try {
	      TimeUnit.SECONDS.sleep(4);
	    } catch (InterruptedException e) {
	      e.printStackTrace();
	    }
	    System.out.printf("Data sources loading has finished: %s\n",new Date());
	}

	public static void main(String[] args){
		DataSourcesLoader dsLoader = new DataSourcesLoader();
	    Thread thread1 = new Thread(dsLoader,"DataSourceThread");

	    thread1.start();

	    try {
	        thread1.join();
	      } catch (InterruptedException e) {
	        e.printStackTrace();
	      }

	      System.out.printf("Main: Configuration has been loaded: %s\n",new Date());
	}

}

执行结果:

Beginning data sources loading: Fri Nov 14 14:27:31 CST 2014
Data sources loading has finished: Fri Nov 14 14:27:35 CST 2014
Main: Configuration has been loaded: Fri Nov 14 14:27:35 CST 2014

如果去掉thread1.join(),执行的结果如下:

Main: Configuration has been loaded: Fri Nov 14 14:28:33 CST 2014
Beginning data sources loading: Fri Nov 14 14:28:33 CST 2014
Data sources loading has finished: Fri Nov 14 14:28:37 CST 2014

通过结果,就可以很明显的说明上面红字的部分:“再来继续执行Thread.join()后面的代码

例2:

package com.example;

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class DataSourcesLoader implements Runnable{

	@Override
	public void run() {
		System.out.printf("Beginning data sources loading: %s\n",new Date());
	    try {
	      TimeUnit.SECONDS.sleep(4);
	    } catch (InterruptedException e) {
	      e.printStackTrace();
	    }
	    System.out.printf("Data sources loading has finished: %s\n",new Date());
	}

	public static void main(String[] args){
		DataSourcesLoader dsLoader = new DataSourcesLoader();
	    Thread thread1 = new Thread(dsLoader,"DataSourceThread");

	    thread1.start();

	    try {
	        thread1.join(3000);
	      } catch (InterruptedException e) {
	        e.printStackTrace();
	      }

	      System.out.printf("Main: Configuration has been loaded: %s\n",new Date());
	}

}

这里使用的是:

thread1.join(3000);

这句话的意思是,只要满足下面2个条件中的一个时,主线程就会继续执行thread.join()后面的代码:

条件1:thread1 执行完毕;

条件2:已经等待 thread1 执行了3000ms.

例子中,thread1 自身的执行时间是4s,而设置的等待时间是3s,所以得到的执行结果如下,thread1还没有执行完,主线程就开始执行后面的代码,因为 thread1 等待的时间已经超时了:

Beginning data sources loading: Fri Nov 14 14:35:45 CST 2014
Main: Configuration has been loaded: Fri Nov 14 14:35:48 CST 2014
Data sources loading has finished: Fri Nov 14 14:35:49 CST 2014

那么结合上面的2个例子,我们可以推断出下面代码的执行结果了:

例3:

package com.example;

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class DataSourcesLoader implements Runnable{

	@Override
	public void run() {
		System.out.printf("Beginning data sources loading: %s\n",new Date());
	    try {
	      TimeUnit.SECONDS.sleep(4);
	    } catch (InterruptedException e) {
	      e.printStackTrace();
	    }
	    System.out.printf("Data sources loading has finished: %s\n",new Date());
	}

}
package com.example;

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class NetworkConnectionsLoader implements Runnable{

	@Override
	public void run() {
		System.out.printf("Beginning network connect loading: %s\n",new Date());
	    try {
	      TimeUnit.SECONDS.sleep(6);
	    } catch (InterruptedException e) {
	      e.printStackTrace();
	    }
	    System.out.printf("Network connect loading has finished: %s\n",new Date());

	}

	public static void main(String[] args){
		DataSourcesLoader dsLoader = new DataSourcesLoader();
	    Thread thread1 = new Thread(dsLoader,"DataSourceThread");

	    NetworkConnectionsLoader ncLoader = new NetworkConnectionsLoader();
	    Thread thread2 = new Thread(ncLoader,"NetworkConnectionLoader");

	    thread1.start();
	    thread2.start(); 

	    try {
	        thread1.join();
	        thread2.join(1900);
	      } catch (InterruptedException e) {
	        e.printStackTrace();
	      }

	      System.out.printf("Main: Configuration has been loaded: %s\n",new Date());
	}

}

执行结果:

Beginning data sources loading: Fri Nov 14 14:39:20 CST 2014
Beginning network connect loading: Fri Nov 14 14:39:20 CST 2014
Data sources loading has finished: Fri Nov 14 14:39:24 CST 2014
Main: Configuration has been loaded: Fri Nov 14 14:39:26 CST 2014
Network connect loading has finished: Fri Nov 14 14:39:26 CST 2014

注意:如果把例3的 thread2.join(1900) 部分修改为:

thread2.join(3000);

结果会和上面的一样吗?

根据我最开始指出的“Thread.join(),是用来指定当前主线程等待其他线程执行完毕后,再来继续执行Thread.join()后面的代码。

我们可以看到,执行结果会有差别:

Beginning data sources loading: Fri Nov 14 14:41:21 CST 2014
Beginning network connect loading: Fri Nov 14 14:41:21 CST 2014
Data sources loading has finished: Fri Nov 14 14:41:25 CST 2014
Network connect loading has finished: Fri Nov 14 14:41:27 CST 2014
Main: Configuration has been loaded: Fri Nov 14 14:41:27 CST 2014</span>

至于为什么会有这个差别,我上面也已经说明了,我想这个应该不难理解。

PS:代码部分截取来自《Java 7 Concurrency Cookbook》

时间: 2024-08-08 18:36:53

Thread.join()方法解析的相关文章

java中synchronize锁 volatile thread.join()方法的使用

对于并发工作,你永远不知道一个线程何时运行,你需要某种方式来避免两个任务访问相同的资源,即要避免资源竞争,至少在关键代码上不能出现这样的情况,否则多个线程同时对某个内存区域操作会导致数据破坏. 程序代码中的临界区是需要互斥访问的,同一时刻只能有一个线程来访问临界区,也就是线程对临界区的访问时互斥的. 竞争条件:当多个线程同时访问某个共享的内存区域并且对其进行读写操作时,就会出现数据破坏.这就是竞争条件.避免竞争条件的方法是synchronized加锁. 样例,设有一个现成,该线程的任务是对共享变

Thread.Join() 方法

1. 什么是 the calling thread? 2. 什么是 a thread? 运行一个程序,即开启了一个进程和至少一个线程,干活的是线程而非进程!the calling thread 我们可以认为是MainThread(或者调用线程的线程,是不是有点绕?呵呵),a thread 我们就认为是被调用的线程. 最后,我们可以这样翻译MSDN:当 a thread 调用Join方法的时候,MainThread 就被停止执行,直到 a thread 线程执行完毕. 下面是测试代码: using

java--java.lang.Thread.join() 方法

Thread类join()方法重载了3次.分别是 join()throws InterruptedException; //无参数的join()等价于join(0),作用是一直等待该线程死亡 join(long millis, int nanos) throws InterruptedException;  //最多等待该线程死亡millis毫秒 join(long millis, int nanos) throws InterruptedException ; //最多等待该线程死亡milli

thread.join() 方法存在的必要性是什么?

好久远的问题,为什么关注这个问题的人这么少? 或许是用到这个功能的情形比较少吧. 1.等待处理结果 为什么要用join()方法在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了.当只有一个主线程和一个子线程的情况这个说法似乎站不住脚,那就往↓↓看 2.未捕获的异常 java多线程程序中所有线程都不允许抛

浅析Thread的join() 方法

Thread中的 join() 方法在实际开发过程中可能用的不是很多,但是在面试中作为考察基本功知识的扎实与否,经常会被用到.因此,对于 Thread 的 join() 方法进行了一定的研究. 常见的一种情景是如何保证创建多个线程保证其按照指定的顺序执行,最简单的一种方法是采用Thread.join() 方法来实现.以下是写的创建若干个线程的示例代码,通过采用创建一个实体类,重写其里面的run 方法来实现.如果指定少数的线程数,可以直接采用 thread.join()来实现,其原理是一致的. 1

注意!你的Thread.Abort方法真的让线程停止了吗?

大家都知道在C#里面,我们可以使用 Thread.Start方法来启动一个线程,当我们想停止执行的线程时可以使用Thread.Abort方法来强制停止正在执行的线程,但是请注意,你确定调用了Thread.Abort方法后线程就立刻停止了吗? 答案是:不是! 下面我们来解释一下Abort方法是如何工作的.因为公用语言运行时管理了所有的托管的线程,同样它能在每个线程内抛出异常.Abort方法能在目标线程中抛出一个ThreadAbortException异常从而导致目标线程的终止.不过Abort方法被

Java 并发:Thread 类深度解析

摘要: Java 中 Thread类 的各种操作与线程的生命周期密不可分,了解线程的生命周期有助于对Thread类中的各方法的理解.一般来说,线程从最初的创建到最终的消亡,要经历创建.就绪.运行.阻塞 和 消亡 五个状态.在线程的生命周期中,上下文切换通过存储和恢复CPU状态使得其能够从中断点恢复执行.结合 线程生命周期,本文最后详细介绍了 Thread 各常用 API. 一. 线程的生命周期 Java 中 Thread类 的具体操作与线程的生命周期密不可分,了解线程的生命周期有助于对Threa

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

class TestThread { private static void FirstThreadFun() { for (int i = 0; i < 10; i++) { Console.WriteLine(Thread.CurrentThread.Name + " i = " + i); } Console.WriteLine(Thread.CurrentThread.Name + " 执行完毕"); } static void Main(string

04 Thread的方法(源代码) 和 线程的状态

  1 .Thread中重要的属性 1 publicclass Thread implements Runnable { //继承自Runnable接口private char name[]; // 以char数组保存线程的名字 2 private int priority; // 线程优先级别 3 /* Whether or not the thread is a daemon thread. */ 4 private boolean daemon = false; //是否为守护线程 5 /