join底层是用wait实现的,使用了并发设计模式中的保护性暂停模式。
join的用法很简单,在线程t1中调用t2.join(),代表t1线程会等待t2线程执行结束。如果加个参数timeout,代表最多等待timeout就不等了。
在看源码之前,需要搞清楚当前运行的线程和调用方法的线程的区别。下面这个案例中,在main线程中调用t1.function(),那么执行到function()方法内部时,当前线程仍然是main,调用function的线程对象是t1。
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestThread t1 = new TestThread("t1");
t1.start();
t1.function();
}
}
class TestThread extends Thread{
public TestThread(String name) {
setName(name);
}
@Override
public void run() {
super.run();
while (true);
}
public void function() {
System.out.println("当前线程:" + currentThread().getName()); // 输出main
System.out.println("调用function的对象" + this.getName()); // 输出t1
}
}
上面的案例弄懂了,来看一下join的源码。假设在t1中调用t2.join()。那么当前线程仍然是t1,调用join的线程对象是t2。而wait方法是让当前线程等待,所以在这里就是让t1线程等待。而isAlive是判断调用join的线程是否存活,也就是这里的t2。如果这些都弄明白了那源码也就很简单了。
// join执行完毕则说明t2线程已经终止
public final synchronized void join(final long millis) throwsInterruptedException {
if (millis > 0) { // 以下是保护性暂停的经典代码
if (isAlive()) {
final long startTime = System.nanoTime();
long delay = millis;
do {
wait(delay);
} while (isAlive() && (delay = millis -
TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0); // 如果t2存活且没超时,则让t1等待delay
}
} else if (millis == 0) {
while (isAlive()) { // 如果t2存活
wait(0); // 就让t1等待
}
} else {
throw new IllegalArgumentException("timeout value is negative");
}
}