join是线程的一个方法,在API中,它的英文解释是Waits for this thread to die.等待此线程死亡。谁等待此线程死亡呢?不难看出,这过程中至少存在两个线程,一个调用线程的线程,一个被调用的线程。我们通过一个简单的示例来理解这句话。
package com.doufu.thread.t01; class ThreadA extends Thread{ private String name; public ThreadA(String name){ this.name = name; } @Override public void run() { try { Thread.sleep(1000);//让此线程等待1秒 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name); } } public class JoinTest01 { public static void main(String[] args) throws InterruptedException { ThreadA t = new ThreadA("T1"); t.start(); t.join(); System.out.println("main"); } }
在上面代码中,调用线程的线程是main即主线程,被调用的线程是t。t.join()的意思即等待t的死亡(运行结束),等待t运行结束的线程就是main。所以上面的代码执行结果应该是先打印T1,再打印main。
通过以上代码,可以理解,在A线程中调用另外一个线程B的join方法,即让线程A进入Block状态,直到线程B运行结束。下面再看一个示例:
只贴出了修改的部分
public class JoinTest01 { public static void main(String[] args) throws InterruptedException { ThreadA t = new ThreadA("T1"); t.join(); t.start(); System.out.println("main"); } }
运行结果:
看这输出结果,是不是觉得不对,不是好说了,在main中调用t的join方法,会让main先挂起,直到t执行结束吗,怎么先打印main了呢?我们来看下Thread类的join源码:
public final void join() throws InterruptedException { join(0); }
join(),实际上是调用另外一个join(long millis)的方法,我们再来看下join(long millis)方法
public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) {//进入这里 while (isAlive()) {//线程必须是活着的 wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
从源码中看出,如果调用join()方法时,线程不是活着的,则无效。以下是isAlive()的源码,注意看下方法注释
/** * Tests if this thread is alive. A thread is alive if it has * been started and has not yet died. * * @return <code>true</code> if this thread is alive; * <code>false</code> otherwise. */ public final native boolean isAlive();
我们来看一个面试题:
写道
现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?
此面试题,我们可以用join来实现
class ThreadA extends Thread{ private String name; public ThreadA(String name){ this.name = name; } @Override public void run() { try { Thread.sleep(1000);//让此线程等待1秒 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name); } } class ThreadB extends Thread{ private String name; private Thread thread; public ThreadB(String name,Thread thread){ this.name = name; this.thread = thread; } @Override public void run() { try { thread.join();//让此线程进入Block Thread.sleep(1000);//让此线程等待1秒 } catch (InterruptedException e1) { e1.printStackTrace(); } System.out.println(name); } } public class JoinTest01 { public static void main(String[] args) throws InterruptedException { ThreadA t1 = new ThreadA("T1"); ThreadB t2 = new ThreadB("T2",t1); ThreadB t3 = new ThreadB("T3",t2); t1.start(); t2.start(); t3.start(); } }
运行结果:
以下更简单的实现方式:
public class JoinTest { static class JoinThread implements Runnable{ private String name; public JoinThread(String name){ this.name = name; } @Override public void run() { System.out.println(name); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("结束"+name); } } public static void main(String[] args) throws Exception { for(int i=0;i<3;i++){ Thread t = new Thread(new JoinThread("t"+i)); t.start(); t.join(); } System.out.println("HAHAHA"); } }
运行结果:
import java.util.concurrent.CountDownLatch; public class CoutDownLatchTest { private static final CountDownLatch c1 = new CountDownLatch(1); private static final CountDownLatch c2 = new CountDownLatch(2); public static void main(String[] args) { Thread t1 = new Thread(){ public void run(){ System.out.println("结束"+1); c1.countDown(); c2.countDown(); } }; Thread t2 = new Thread(){ public void run(){ try { c1.await(); System.out.println("结束"+2); c2.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread t3 = new Thread(){ public void run(){ try { c2.await(); System.out.println("结束"+3); } catch (InterruptedException e) { e.printStackTrace(); } } }; t3.start(); t2.start(); t1.start(); System.out.println("HAHAHA"); }
相关推荐
本压缩包,总共包含两个文档,JAVA多线程编程详解-详细操作例子和 Java多线 程编程总结 例如,runnable、thread、stop()、 suspend、yield、setPriority()、getPriority()、synchronized、wait()、join、线程池同步...
Java线程中wait、await、sleep、yield、join用法汇总,文章里面总结了这些关键字的用法,并且里面带有源码帮助分析用法,此一文就可以理解这些关键字用法,推荐拥有
【IT十八掌徐培成】Java基础第08天-02.多线程-join-daemon-同步.zip
在char01包里放置Java多线程基本知识的代码。内容如下: 如何使用多线程 如何得到多线程的一些信息 如何停止线程 如何暂停线程 线程的一些其他用法 在char02包里放置了Java对变量和对象并发访问的知识的代码...
主要介绍了JAVA多线程之方法 JOIN详解及实例代码的相关资料,需要的朋友可以参考下
下面小编就为大家带来一篇浅谈java多线程 join方法以及优先级方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
看完《think in java》多线程章节,自己写的多线程文档,还结合了其他的相关网络资料。 线程 一. 线程池 1)为什么要使用线程池 2 2)一个具有线程池的工作队列 3 3)使用线程池的风险: 4 4)有效使用线程池的原则 5...
java Fork Join框架及使用,java自带的多线程框架,来处理多线程的问题
本文对java Thread中join()方法进行介绍,join()的作用是让“主线程”等待“子线程”结束之后才能继续运行,大家参考使用吧
多线程 进程和线程 并发和并行 多线程的利弊 什么是上下文切换? 线程的优先级 线程的几种状态 sleep方法和wait方法的区别 stop,suspend,resume等方法为什么会被遗弃 interrupt,interrupted,isInterrupted方法区别 ...
7、 浅析 Java Thread.join() : java多线程实现主线程等待所有子线程执行完毕 16 8、 线程运行中抛出异常的处理 19 9、 Callable 有返回值的线程 20 10、 Callable结合FutureTask的多线程使用(免打扰模式) 24
主要介绍了Java多线程join方法实例代码,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
Java实验指导书_多线程 《Java语言程序设计基础教程》 上机实验指导手册 异常处理 【目的】 ①线程的创建和运行 ②Thread类的sleep、join等方法的使用 ③线程同步
C#多线程实验,就AutoResetEvent,ManualResetEvent,Thread.join(),委托多线程回调。
文章目录1、进程与线程2、创建多线程2.1、继承Thread类2.2、实现Runnable接口2.3、使用匿名内部类实现2.4、实现Runnable接口的好处2.5、使用Callable和Future创建线程3、线程的生命周期4、几种特殊线程4.1、join线程...
这段代码实现了一个下载器,可以同时下载多个文件。其中,构造函数MultiThreadDownloader接收一个URL数组和两个整数数组作为参数,分别表示每个URL的起始...最后,通过调用每个线程的join()方法等待所有线程执行完毕。
长期以来,多线程问题颇为受到面试官的青睐。虽然我个人认为我们当中很少有人能真正获得机会开发复杂的多线程应用(在过去的七年中,我得到了一个机会),但是理解多线程对增加你的信心很有用。之前,我讨论了一个wait...
本文通过实例代码给大家实例介绍了Java多线程中关于join方法的使用,非常不错,具有参考借鉴价值,需要的朋友参考下
第3章 多线程(二) Java 高级程序设计 Java高级程序设计-多线程(二)全文共34页,当前为第1页。 回顾 进程一般代表一个应用程序,一个进程中可以包含多个线程。 合理使用多线程能够提高程序的执行效率,处理高并发...
join方法的功能就是使异步执行的线程变成同步执行。也就是说,当调用线程实例的start方法后,这个方法会立即返回,如果在调用start方法后后需要使用一个由这个线程计算得到的值,就必须使用join方法