Java多线程之join
程序员文章站
2022-07-12 19:29:02
...
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"); }