1、join()介绍
join() 定义在Thread.java中,join() 的作用是让“父线程”等待“子线程”结束之后再继续运行,示例:
public class FatherThread extends Thread {
public FatherThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println("父线程开始>>>>>");
SunThread st = new SunThread("st");
st.start();
try {
st.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("父线程结束>>>>>");
}
}
class SunThread extends Thread {
public SunThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println("子线程开始>>>>>");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程结束>>>>>");
}
}
//测试
public static void main(String args[]) {
FatherThread ft = new FatherThread("ft");
ft.start();
}
//结果
父线程开始>>>>>
子线程开始>>>>>
子线程结束>>>>>//5秒后打印
父线程结束>>>>>
在调用st.join()之后,ft父线程会一直等待,直到“子线程st”运行完毕,在“子线程st”运行完毕之后,父线程才能接着运行
2、join()方法的源码
public final void join() throws InterruptedException {
join(0);
}
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;
}
}
}
源码分析:当millis==0时,会进入while(isAlive())循环——即只要子线程是活的,主线程就不停的等待
①我们经常调用的join()实际上调用的是join(0)
②join(long millis)是一个同步方法,该方法的锁是线程对象本身,因为我们通常都是调用子线程的join(),因此此同步方法的锁是子线程对象本身(而不是父线程),在父线程中调用了子线程的join()方法之后,父线程就获取到了子线程这个对象的同步锁,我们可以看到在join(long millis)方法中调用了wait(long millis)(注意是子线程对象的wait()),这会使父线程等待——因为此时父线程持有子线程对象为锁,直到超过join规定的时间或者子线程执行结束
③如果想使父线程中同时启动多个子线程(使这几个子线程并行执行),并想确保让某个子线程先于父线程执行完成,应该在调用完所有子线程的start()后调用该子线程的join(),因为如果先调用join()会使父线程等待,而可能导致其他子线程还没有start,只能等到该join的子线程执行完之后父线程获取执行权然后再调用子线程的start启动其他子线程
④父线程中可以同时调用多个子线程的join(),这些join()方法的执行应该是顺序的,因为每调用一个子线程的join(),父线程都会wait,但这不意味着这些子线程不能并发执行,只要调用了子线程的start,那么所有start后的子线程都会并发执行,join的作用是保证该子线程先于父线程执行完