使用
public static void main(String[] args) throws Exception {
System.out.println("start");
Thread t = new Thread() {
@Override
public void run() {
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("middle");
}
};
t.start();
t.join();
System.out.println("end");
}
输出结果:
start
middle
end
源码解析
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) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
总结:
- 线程非活状态下,join无作用;所以join在线程未启动前和执行完成后均无作用
- join中为什么要使用while,用while的后果呢?使用while是为了防止自定义Thread进行唤醒;while导致阻塞,无法释放锁和CPU
- 线程执行完为什么会唤醒?
线程执行完成后,JVM会执行exit,在exit中唤醒,看源码:
// 位于/hotspot/src/share/vm/runtime/thread.cpp中
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
...
ensure_join(this); // 有一个贼不起眼的一行代码,就是这行
...
}
static void ensure_join(JavaThread* thread) {
...
lock.notify_all(thread); // thread就是当前线程,是啥?就是刚才例子中说的t1线程啊。
...
}
提醒:join中的wait根本不是ThreadGroup代码中进行的唤醒,锁的对象都不是一个
void threadTerminated(Thread t) {
synchronized (this) {
remove(t);
if (nthreads == 0) {
notifyAll();
}
if (daemon && (nthreads == 0) &&
(nUnstartedThreads == 0) && (ngroups == 0))
{
destroy();
}
}
}