thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

t.join();      //使调用线程 t 在此之前执行完毕。
t.join(1000);  //等待 t 线程,等待时间是1000毫秒

先上一段JDK中代码:

  1. /**
  2. *  Waits at most <code>millis</code> milliseconds for this thread to
  3. * die. A timeout of <code>0</code> means to wait forever.
  4. */
  5. //此处A timeout of 0 means to wait forever 字面意思是永远等待,其实是等到t结束后。
  6. public final synchronized void join(long millis)    throws InterruptedException {
  7. long base = System.currentTimeMillis();
  8. long now = 0;
  9. if (millis < 0) {
  10. throw new IllegalArgumentException("timeout value is negative");
  11. }
  12. if (millis == 0) {
  13. while (isAlive()) {
  14. wait(0);
  15. }
  16. } else {
  17. while (isAlive()) {
  18. long delay = millis - now;
  19. if (delay <= 0) {
  20. break;
  21. }
  22. wait(delay);
  23. now = System.currentTimeMillis() - base;
  24. }
  25. }
  26. }

从代码上看,如果线程被生成了,但还未被起动,调用它的 join() 方法是没有作用的,将直接继续向下执行

Join方法实现是通过wait(小提示:Object 提供的方法)。 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程 ,比如退出后。这就意味着main 线程调用t.join时,必须能够拿到线程t对象的锁

Example1:

  1. public class JoinTest implements Runnable{
  2. public static int a = 0;
  3. public void run() {
  4. for (int k = 0; k < 5; k++) {
  5. a = a + 1;
  6. }
  7. }
  8. public static void main(String[] args) throws Exception {
  9. Runnable r = new JoinTest();
  10. Thread t = new Thread(r);
  11. t.start();
  12. System.out.println(a);
  13. }
  14. }

请 问程序的输出结果是5吗?答案是:有可能。其实你很难遇到输出5的时候,通常情况下都不是5。当然这也和机器有严重的关系。为什么呢?我的解释是当主线程 main方法执行System.out.println(a);这条语句时,线程还没有真正开始运行,或许正在为它分配资源准备运行。因为为线程分配资源需要时间,而main方法执行完t.start()方法后继续往下执行System.out.println(a);,这个时候得到的结果是a还没有被 改变的值0 。怎样才能让输出结果为5!其实很简单,join() 方法提供了这种功能。join() 方法,它能够使调用该方法的线程在此之前执行完毕。

  1. public static void main(String[] args) throws Exception {
  2. Runnable r = new JoinTest();
  3. Thread t = new Thread(r);
  4. t.start();
  5. t.join(); //加入join()
  6. System.out.println(a);
  7. }

这个时候,程序输入结果始终为5。

为 了证明如果不使用t.join()方法,主线程main方法的System.out.println(a);语句将抢先执行,我们可以在main方法中加入一个循环,这个循环用来延长main方法执行的时间,循环次数将严重取决于机器性能。如果循环次数得当,我们也可以看到a的输出结果是5。

  1. public static void main(String[] args) throws Exception {
  2. Runnable r = new JoinTest();
  3. Thread t = new Thread(r);
  4. t.start();
  5. //t.join(); //加入join()
  6. /*
  7. 注意循环体内一定要有实际执行语句,否则编译器或JVM可能优化掉你的这段代码,视这段代
  8. 码为无效。
  9. */
  10. for (int i=0; i<300; i++) {
  11. System.out.print(i);
  12. }
  13. System.out.println();
  14. System.out.println(a);
  15. }

经自己测试,最后a一直是5.

本例参考:http://agio.iteye.com/blog/210600

Example2:join(n)

  1. class RunnableImpl implements Runnable {
  2. public void run() {
  3. try {
  4. System.out.println("Begin sleep");
  5. Thread.sleep(1000);
  6. System.out.println("End sleep");
  7. } catch (InterruptedException e) {
  8. e.printStackTrace();
  9. }
  10. }
  11. }
  1. public class JoinTest{
  2. public static void main(String[] args) {
  3. Thread t = new Thread(new RunnableImpl());
  4. t.start();
  5. try {
  6. t.join(1000);
  7. System.out.println("joinFinish");
  8. } catch (InterruptedException e) {
  9. e.printStackTrace();
  10. }
  11. }
  12. }

结果是:
Begin sleep
End sleep
joinFinish

明白了吧,当main线程调用t.join时,main线程等待t线程,等待时间是1000,如果t线程Sleep 2000呢

  1. class RunnableImpl implements Runnable {
  2. public void run() {
  3. try {
  4. System.out.println("Begin sleep");
  5. Thread.sleep(2000); //原来为1000
  6. System.out.println("End sleep");
  7. } catch (InterruptedException e) {
  8. e.printStackTrace();
  9. }
  10. }
  11. }

结果是:
Begin sleep
joinFinish
End sleep
也就是说main线程只等1000毫秒,不管T什么时候结束.

参考:http://blog.csdn.net/FG2006/archive/2011/05/04/6393768.aspx

Example3:

  1. class CustomThread1 extends Thread {
  2. public void run() {
  3. String threadName = Thread.currentThread().getName();
  4. System.out.println(threadName + " start.");
  5. try {
  6. for (int i = 0; i < 5; i++) {
  7. System.out.println(threadName + " loop at " + i);
  8. Thread.sleep(1000);
  9. }
  10. System.out.println(threadName + " end.");
  11. } catch (Exception e) {
  12. System.out.println("Exception from " + threadName + ".run");
  13. }
  14. }
  15. }
  16. class CustomThread extends Thread {
  17. CustomThread1 t1;
  18. public CustomThread(CustomThread1 t1) {
  19. this.t1 = t1;
  20. }
  21. public void run() {
  22. String threadName = Thread.currentThread().getName();
  23. System.out.println(threadName + " start.");
  24. try {
  25. t1.join();
  26. System.out.println(threadName + " end.");
  27. } catch (Exception e) {
  28. System.out.println("Exception from " + threadName + ".run");
  29. }
  30. }
  31. }
  32. public class JoinTestDemo {
  33. public static void main(String[] args) {
  34. String threadName = Thread.currentThread().getName();
  35. System.out.println(threadName + " start.");
  36. CustomThread1 t1 = new CustomThread1();
  37. CustomThread t = new CustomThread(t1);
  38. try {
  39. t1.start();
  40. Thread.sleep(2000);
  41. t.start();
  42. t.join(); //在代碼2里,將此處注釋掉
  43. } catch (Exception e) {
  44. System.out.println("Exception from main");
  45. }
  46. System.out.println(threadName + " end!");
  47. }
  48. }

结果:

main start.    //main方法所在的线程起动,但没有马上结束,因为调用t.join();,所以要等到t结束了,此线程才能向下执行。

[CustomThread1] Thread start.     //线程CustomThread1起动
[CustomThread1] Thread loop at 0  //线程CustomThread1执行
[CustomThread1] Thread loop at 1  //线程CustomThread1执行
[CustomThread] Thread start.      //线程CustomThread起动,但没有马上结束,因为调用t1.join();,所以要等到t1结束了,此线程才能向下执行。
[CustomThread1] Thread loop at 2  //线程CustomThread1继续执行
[CustomThread1] Thread loop at 3  //线程CustomThread1继续执行
[CustomThread1] Thread loop at 4  //线程CustomThread1继续执行
[CustomThread1] Thread end.       //线程CustomThread1结束了
[CustomThread] Thread end.        // 线程CustomThread在t1.join();阻塞处起动,向下继续执行的结果

main end!      //线程CustomThread结束,此线程在t.join();阻塞处起动,向下继续执行的结果。

将上例中的join注释掉:

  1. public class JoinTestDemo {
  2. public static void main(String[] args) {
  3. String threadName = Thread.currentThread().getName();
  4. System.out.println(threadName + " start.");
  5. CustomThread1 t1 = new CustomThread1();
  6. CustomThread t = new CustomThread(t1);
  7. try {
  8. t1.start();
  9. Thread.sleep(2000);
  10. t.start();
  11. //t.join();
  12. } catch (Exception e) {
  13. System.out.println("Exception from main");
  14. }
  15. System.out.println(threadName + " end!");
  16. }
  17. }

结果:

main start. // main方法所在的线程起动,但没有马上结束,这里并不是因为join方法,而是因为Thread.sleep(2000);

[CustomThread1] Thread start.      //线程CustomThread1起动
[CustomThread1] Thread loop at 0   //线程CustomThread1执行
[CustomThread1] Thread loop at 1   //线程CustomThread1执行
main end!   // Thread.sleep(2000);结束,虽然在线程CustomThread执行了t1.join();,但这并不会影响到其他线程(这里main方法所在的线程)。
[CustomThread] Thread start.       //线程CustomThread起动,但没有马上结束,因为调用t1.join();,所以要等到t1结束了,此线程才能向下执行。
[CustomThread1] Thread loop at 2   //线程CustomThread1继续执行
[CustomThread1] Thread loop at 3   //线程CustomThread1继续执行
[CustomThread1] Thread loop at 4   //线程CustomThread1继续执行
[CustomThread1] Thread end.       //线程CustomThread1结束了
[CustomThread] Thread end.        // 线程CustomThread在t1.join();阻塞处起动,向下继续执行的结果

本例参考:http://blog.csdn.net/bzwm/archive/2009/02/12/3881392.aspx

Example4 :

main 线程调用t.join时,必须能够拿到线程t对象的锁,如果拿不到它是无法wait的 ,刚开的例子t.join(1000)不是说明了main线程等待1 秒,如果在它等待之前,其他线程获取了t对象的锁,它等待时间可不就是1毫秒了 。

  1. class RunnableImpl implements Runnable {
  2. public void run() {
  3. try {
  4. System.out.println("Begin sleep");
  5. Thread.sleep(2000);
  6. System.out.println("End sleep");
  7. } catch (InterruptedException e) {
  8. e.printStackTrace();
  9. }
  10. }
  11. }
  1. class ThreadTest extends Thread {
  2. Thread thread;
  3. public ThreadTest(Thread thread) {
  4. this.thread = thread;
  5. }
  6. @Override
  7. public void run() {
  8. synchronized (thread) {
  9. System.out.println("getObjectLock");
  10. try {
  11. Thread.sleep(9000);
  12. } catch (InterruptedException ex) {
  13. ex.printStackTrace();
  14. }
  15. System.out.println("ReleaseObjectLock");
  16. }
  17. }
  18. }
  1. public class JoinTest {
  2. public static void main(String[] args) {
  3. Thread t = new Thread(new RunnableImpl());
  4. new ThreadTest(t).start();
  5. t.start();
  6. try {
  7. t.join();
  8. System.out.println("joinFinish");
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. }

结果:
getObjectLock
Begin sleep
End sleep
ReleaseObjectLock
joinFinish

在main方法中 通过new  ThreadTest(t).start()实例化 ThreadTest 线程对象, 它 通过 synchronized  (thread) ,获取线程对象t的锁,并Sleep(9000)后释放,这就意味着,即使main方法t.join(1000)等待一秒钟,它必须等待ThreadTest 线程释放t锁后才能进入wait方法中,它实际等待时间是9000+1000ms。

例子参考Example2来源.

Thread.join()方法的更多相关文章

  1. Java Thread.join()方法

    一.使用方式. join是Thread类的一个方法,启动线程后直接调用,例如: Thread t = new AThread(); t.start(); t.join(); 二.为什么要用join() ...

  2. JAVA THREAD.JOIN方法详解

    一.使用方式. join是Thread类的一个方法,启动线程后直接调用,例如: Thread t = new AThread(); t.start(); t.join(); 二.为什么要用join() ...

  3. 多线程--Thread.join方法

    在Thread类的Api中,Join的作用是让当前线程等待目标线程结束之后才继续执行. thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程.  比如在线程B ...

  4. Java java.lang.Thread#join()方法分析

    结论:A 线程调用 B 线程对象的 join 方法,则 A 线程会被阻塞,直到 B 线程 挂掉 (Java Doc 原话: Watis for this thread to die). 一.分析 查看 ...

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

    好久远的问题,为什么关注这个问题的人这么少? 或许是用到这个功能的情形比较少吧. 1.等待处理结果 为什么要用join()方法在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算 ...

  6. Thread join方法的用途

    主线程中会创建多个子线程做一些事情,主线程要用到这些子线程处理的数据,因此它需要等待所有的子线程处理完之后才继续运行.这就要用到join方法了.

  7. Thread.join方法的解析(转)

    原文链接:https://www.cnblogs.com/huangzejun/p/7908898.html 1. join() 的示例和作用 1.1 示例 1 // 父线程 2 public cla ...

  8. 浅析Thread的join() 方法

    Thread中的 join() 方法在实际开发过程中可能用的不是很多,但是在面试中作为考察基本功知识的扎实与否,经常会被用到.因此,对于 Thread 的 join() 方法进行了一定的研究. 常见的 ...

  9. Thread的join方法

    一个线程在执行的过程中,可能调用另一个线程,前者可以称为调用线程,后者成为被调用线程. Thread.Join方法的使用场景:调用线程挂起,等待被调用线程执行完毕后,继续执行. 如下案列: 当NewT ...

随机推荐

  1. 移动端rem实现响应布局

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. memcache的最佳实践方案

    1.memcached的基本设置 1)启动Memcache的服务器端 # /usr/local/bin/memcached -d -m 10 -u root -l 192.168.0.200 -p 1 ...

  3. 字符串反转----将this is good 转化为good is this 输出。

    思路:现将整个字符串反转,再将每个单词反转: #include "iostream" #include "cstring" using namespace st ...

  4. 找出A字符串中出现B字符串的起始位置

    /** * 找出B出现在A中的起始位置 * @param A * @param lenA * @param B * @param lenB * @date 2016-10-7 * @author sh ...

  5. Java 获取两个日期之间的日期

    1.前期需求,两个日期,我们叫他startDate和endDate,然后获取到两个日期之间的日期 /** * 获取两个日期之间的日期 * @param start 开始日期 * @param end ...

  6. Matlab基本函数-conj函数

    Matlab基本函数-conj函数 1.conj函数:用于计算复数的共轭值 2.用法说明:y=conj(x)函数计算复数x的共轭值.输出结果y的维数跟输入x的维数一致,返回值为:real(y)-i*i ...

  7. Vim命令合集大全

    命令历史 以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令. 启动vim 在命令行窗口中输入以下命令即可 vim 直接启动vim vim filename 打开vim ...

  8. Cellebrite UFED 5.1 发布,全面支持三星 S6 S6 Edge Note5 HUAWEI series

    世界级取证公司Cellebrite 昨天发布了最新的 UFED 5.1 系统更新,4PC全面支持三星S6,S6EDGE NOTE5 以及HUAWEI,LG系列恢复,锁屏密码XX!下面是部分截图 有需要 ...

  9. Linux部署Apache Solr5.5.2+Apache Zookeeper3.4.6

    一.官网下载所需包. solr-5.5.2.tgz 下载地址:https://mirrors.tuna.tsinghua.edu.cn/apache/lucene/solr/5.5.2/ zookee ...

  10. jquery autocomplete

    <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="http: ...