先说结论:阻塞调用线程,等待结果返回,类似于future,本质上是调用了wait
证明例子一:
@Test
public void test() throws InterruptedException {
Thread t = new Thread(() -> {
System.out.println("开始");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束");
});
t.start();
t.join(); //这里是主线程调用,谁调用就阻塞谁
Thread.sleep(2000);
System.out.println("--------------");
}
wait的作用是释放对象锁,释放CUP资源,使当前线程阻塞,进入对象的wait set,直到被通知、被中断或timeout到期。
当前线程指的是调用t.wait(0)方法的线程,很显然是主线程调用的t.join(),进而调用的t.wait(0),所以join是阻塞主(父)线程,而非子线程。
例子二:
@Test
public void learnJoin() throws Exception{
Thread t1 = new Thread("t1"){
@Override
public void run() {
try {
Thread.sleep(100);
System.out.println("------"+this.getName()+"------");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t2 = new Thread("t2"){
@Override
public void run() {
try {
this.join();
Thread.sleep(100);
System.out.println("------"+this.getName()+"------");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t1.start();
t2.start();
Thread.sleep(1000);
System.out.println("11111111");
}
在t2自己的线程内使用this.join()是t2自己调用自己的join(),所以是t2线程阻塞。这里要注意:在junit中主线程执行完就跟子线程一起销毁了,而在main方法中,则不会,主线程销毁,t2线程还是在执行wait
join源码: