赞
踩
join() 是Thread的实例方法,官方解释为:等待该线程终止。
join() 方法的作用就是:将调用join的线程优先执行,当前正在执行的线程阻塞,直到调用join方法的线程执行完毕
或者被打断,主要用于线程之间的交互。
“Java 7 Concurrency Cookbook” 对 join() 方法的定义:
public final void join()throws InterruptedException: Waits for this thread to die.
thread.join() 方法阻塞调用此方法的线程(calling thread),直到线程thread完成,此线程再继续;通常用于在
main() 主线程内,等待其它线程完成再结束 main() 主线程。
另外还有一个应用场景:如何实现让线程T1,T2,T3,在T1执行完成后才执行T2,T2执行完成后才执行T3,
也就是线程的串行化,通过 Thread 类的 join() 方法就可以实现。
代码演示,主要是对比,使用 join()方法前后效果对比。
创建线程 Thread-a 代码:
/** * @title: ThreadA * @description: TODO * @date 2019/6/6 */ public class ThreadA implements Runnable{ private String threadName; private Thread thread; // 构造方法中就启用线程 ThreadA(String threadName) { this.threadName = threadName; thread = new Thread(this, threadName); thread.start(); } @Override public void run() { System.out.println("线程" + Thread.currentThread().getName() + "业务逻辑开始!"); for(int i = 6; i > 0 ; i--) { // 线程睡眠1秒 try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + " : " + i); } catch (Exception e) { System.out.println(Thread.currentThread().getName() + "线程执行异常!"); e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + " 线程结束!"); } public String getThreadName() { return threadName; } public Thread getThread() { return thread; } }
测试代码一:
/** * @title: ThreadMain * @description: TODO * @date 2019/6/6 */ public class ThreadMain { public static void main(String[] args) throws InterruptedException { // 创建线程 B Thread threadB = new Thread(new Runnable() { @Override public void run() { // 启动线程 Thread-a ThreadA threadA = new ThreadA("Thread-a"); try { // 加入 join 方法 threadA.getThread().join(); } catch (InterruptedException e) { e.printStackTrace(); } // 线程B的业务逻辑 System.out.println("开始线程 " + Thread.currentThread().getName() + "业务逻辑"); for (int i = 6; i > 0 ; i--) { try { System.out.println(Thread.currentThread().getName() + " : " + i); // 睡眠0.5秒 Thread.sleep(500); } catch (Exception e) { System.out.println(Thread.currentThread().getName() + " 线程执行异常!"); e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + " 线程结束!"); } }, "Thread-B"); // 启动线程B threadB.start(); // 加入 join 方法 threadB.join(); // 主线程业务逻辑开始 System.out.println("主线程业务逻辑开始"); for (int i = 6; i > 0 ; i--) { try { System.out.println(Thread.currentThread().getName() + " : " + i); // 睡眠0.3秒 Thread.sleep(300); } catch (Exception e) { System.out.println(Thread.currentThread().getName() + " 线程执行异常!"); e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + " 线程结束!"); } }
运行结果一:
测试代码二,仅将测试代码一中的,两次调用 join() 方法部分注释掉,其他部分均一样。
测试代码二:
/** * @title: ThreadMain * @description: TODO * @date 2019/6/6 */ public class ThreadMain { public static void main(String[] args) throws InterruptedException { // 创建线程 B Thread threadB = new Thread(new Runnable() { @Override public void run() { // 启动线程 Thread-a ThreadA threadA = new ThreadA("Thread-a"); // try { // // 加入 join 方法 // threadA.getThread().join(); // } catch (InterruptedException e) { // e.printStackTrace(); // } // 线程B的业务逻辑 System.out.println("开始线程 " + Thread.currentThread().getName() + "业务逻辑"); for (int i = 6; i > 0 ; i--) { try { System.out.println(Thread.currentThread().getName() + " : " + i); // 睡眠0.5秒 Thread.sleep(500); } catch (Exception e) { System.out.println(Thread.currentThread().getName() + " 线程执行异常!"); e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + " 线程结束!"); } }, "Thread-B"); // 启动线程B threadB.start(); // 加入 join 方法 // threadB.join(); // 主线程业务逻辑开始 System.out.println("主线程业务逻辑开始"); for (int i = 6; i > 0 ; i--) { try { System.out.println(Thread.currentThread().getName() + " : " + i); // 睡眠0.3秒 Thread.sleep(300); } catch (Exception e) { System.out.println(Thread.currentThread().getName() + " 线程执行异常!"); e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + " 线程结束!"); } }
运行结果二:
测试代码一和测试代码二,唯一的差别就是:测试代码二将测试代码一中的,两次调用 join() 方法部分注释掉了。
代码中,在线程 Thread-B 中调用了线程 Thread-a ,在主线程 Main 中调用了线程 Thread-B。同时,Thread-a
线程的睡眠时间是 1 秒,Thread-B 线程的睡眠时间是 0.5 秒,Main 线程的睡眠时间是 0.3 秒。
当加入 join() 方法后:由于Thread-B 线程中调用 Thread-a,优先执行Thread-a 线程,当前正在执行的Thread-B
线程堵塞,直到Thread-a 线程执行完毕。同理,由于Main 主线程中调用 Thread-B线程,故优先执行Thread-B 线程,
当前正在执行的 Main 主线程堵塞,直到Thread-B 线程执行完毕。
总结:
join() 方法的作用就是:将调用join的线程优先执行,当前正在执行的线程阻塞,直到调用join方法的线程执行完毕
或者被打断,主要用于线程之间的交互.
深入源码了解一下join(),这里仅截取 Thread 类 的 join() 和 join(millis) 方法
package java.lang; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.security.AccessController; import java.security.AccessControlContext; import java.security.PrivilegedAction; import java.util.Map; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.LockSupport; import sun.nio.ch.Interruptible; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; public class Thread implements Runnable { …… …… /** 这里仅截取 Thread 类 的 join() 和 join(millis) 方法 */ …… /** * Waits for this thread to die. * * <p> An invocation of this method behaves in exactly the same * way as the invocation * * <blockquote> * {@linkplain #join(long) join}{@code (0)} * </blockquote> * * @throws InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when this exception is thrown. */ public final void join() throws InterruptedException { join(0); } /** * Waits at most {@code millis} milliseconds for this thread to * die. A timeout of {@code 0} means to wait forever. * * <p> This implementation uses a loop of {@code this.wait} calls * conditioned on {@code this.isAlive}. As a thread terminates the * {@code this.notifyAll} method is invoked. It is recommended that * applications not use {@code wait}, {@code notify}, or * {@code notifyAll} on {@code Thread} instances. * * @param millis * the time to wait in milliseconds * * @throws IllegalArgumentException * if the value of {@code millis} is negative * * @throws InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when this exception is thrown. */ 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) { // 无限期等待直到b线程结束 while (isAlive()) { // wait操作,那必然有synchronized与之对应, // 成员方法加了synchronized说明是synchronized(this)。 // 注意这个wait()方法是Object类中的方法 wait(0); } } else { // 等待固定时间,如果b没结束,那么就不等待了。 while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
线程模块,计划用一个系列博文整理总结。上一篇博文: 《线程系列1:创建线程》
本文在源码理解部分,参考了博文: 【Java】Thread类中的join()方法原理. 非常感谢博主!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。