join()
表示一个线程会无限等待至被等待线程死亡为止。
join(long)
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(long)表示一个线程最多等待long的时间,如果被等待线程超过这个时间还不死亡就不再等待了。但是,查看源码可以发现,join(long)内部是通过wait()来实现的,而wait()必须获得对象的锁。我们定义一个线程b,还有Main主线程,当在主线程执行b.join(2000)的时候,主线程一定暂停两秒吗?答案是否定的,通过阅读源码可以知道,当主线程执行b.join(2000)的时候是有一个争锁的过程的,如果没有争到锁就必须等待,而这次的等待时间是不算入计数的时间的,所以这就有可能造成主线程等待的时间比规定的时间长。当超过了规定的long时间,join(long)就会开始第二次争锁(从wait()苏醒也必须获得锁)。如果此时还是争不到锁,join(long)就无法通知主线程继续执行后面的代码,主线程继续等待。只有当join(long)争到锁了,向主线程发起通知,主线程才能继续执行。期间等待的过程也可能会超过规定的long时间。综上所诉,join(long)不一样等待时间小于等于long,还有可能大于long。
这是一个验证的例子
package test;
class ThreadA extends Thread{
public void run() {
synchronized (this) {
try {
System.out.println("睡眠5秒");
Thread.sleep(5000);
System.out.println("睡完了");
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
try {
System.out.println("再睡眠5秒");
Thread.sleep(5000);
System.out.println("睡完了");
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
ThreadA a = new ThreadA();
a.start();
a.join(2000);
long end = System.currentTimeMillis();
System.out.println("不等了");
System.out.println("共运行" + (end - start)/1000 + "秒");
}
}