1.用法
join是Thread类的一个方法,启动线程后直接调用,例如:
Thread t = new AThread();
t.start();
t.join();
2.join方法的作用
在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。
即join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。
3.示例
package com.roocom.test2;
/**
*
* @author yanling
* @time 2019-2-21 00:41:08
*/
public class TestDemo {
public static void main(String[] args) {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 开始执行...");
BThread bt = new BThread();
bt.setName("线程bt");
AThread at = new AThread(bt);
at.setName("线程at");
try {
bt.start();
Thread.sleep(2000);
System.out.println("暂停2秒");
at.start();
at.join();
} catch (Exception e) {
System.out.println("Exception from main");
}
System.out.println(threadName + " 执行结束...");
}
}
class BThread extends Thread {
public BThread() {
super("[BThread] Thread");
};
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 开始执行...");
try {
for (int i = 0; i < 5; i++) {
System.out.println(threadName + " loop at " + i);
Thread.sleep(1000);
}
System.out.println(threadName + " 运行结束...");
} catch (Exception e) {
System.out.println("Exception from " + threadName + ".run");
}
}
}
class AThread extends Thread {
BThread bt;
public AThread(BThread bt) {
super("[AThread] Thread");
this.bt = bt;
}
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 开始执行...");
try {
bt.join();
System.out.println(threadName + " 执行结束...");
} catch (Exception e) {
System.out.println("Exception from " + threadName + ".run");
}
}
}
执行结果
main 开始执行...
线程bt 开始执行...
线程bt loop at 0
线程bt loop at 1
暂停2秒
线程at 开始执行...
线程bt loop at 2
线程bt loop at 3
线程bt loop at 4
线程bt 运行结束...
线程at 执行结束...
main 执行结束...
修改下mian方法,使得mian线程不需要等待线程at。
public class TestDemo {
public static void main(String[] args) {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 开始执行...");
BThread bt = new BThread();
bt.setName("线程bt");
AThread at = new AThread(bt);
at.setName("线程at");
try {
bt.start();
Thread.sleep(2000);
System.out.println("暂停2秒");
at.start();
// at.join(); 注释掉这行,使mian线程不需要等待线程at执行结束
} catch (Exception e) {
System.out.println("Exception from main");
}
System.out.println(threadName + " 执行结束...");
}
}
运行结果
线程bt loop at 0
线程bt loop at 1
暂停2秒
线程bt loop at 2
main 执行结束...
线程at 开始执行...
线程bt loop at 3
线程bt loop at 4
线程bt 运行结束...
线程at 执行结束...
4.源码解读
进入bt.join方法看一下它的JDK源码:
/**
* 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);
}
我们再进入到join方法里面去
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) { //如果时执行的join(0)
while (isAlive()) { //如果线程是运行状态,就会执行下面的等待
wait(0);
}
} else { //如果是执行的join(time)
while (isAlive()) { //如果线程时运行状态
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay); //等待delay时间后自动返回继续执行
now = System.currentTimeMillis() - base;
}
}
}
通过源码我们可以看到,其核心代码就是下面这段
while (isAlive()) { //调用join方法线程是运行时状态
wait(0); //进入等待
}
源码中while(isAlive()),其实相当于while(this.isAlive())校验线程是不是运行状态,如果是就执行wait(0),wait(0)是什么意思呢,查看下面wait()方法源码,其实wait()方法就是调用了wait(0)方法实现的,wait(0)就是让其一直等待。到这里会发现,其实join方法本质就是利用上面的线程实例作为对象锁的原理,当线程终止时,会调用线程自身的notifyAll()方法,通知所有等待在该线程对象上的线程的特征。