join方法源码
join方法的作用是让当前线程等待另一个线程执行完,主要应用于多个线程需要按照指定顺序执行的场景。
public final void join() throws InterruptedException {
join(0);
}
查看Thread类中join()方法发现实际调用的是重载方法join(long millis)并且参数是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;
}
}
}
首先对其中的几个变量进行解释:
base:记录开始等待的时间now:已经等待的时间millis:一共要等待的时间delay:剩余要等待的时间isAlive():查看线程是否存活wait():当前线程进行等待
受
wait方法的影响,我开始一直认为isAlive方法是查看当前线程的存活状态,所以逻辑上就一直搞不通。后来我理解的是t1.isAlive()是查看t1线程是否存活,而不是当前线程
情景一:main线程调用t1.join()
t1.join()实际调用的是t1.join(0),进入方法后会执行到①处的if语句中,这里的while循环换一种写法就容易理解了
while(t1.isAlive()) {
t1.wait(0);
}
也就是说去查看t1线程是否存活,如果存活的话就让当前main线程一直等待,所以等t1线程执行完之后t1.isAlive()结果为false,main线程就不再等待可以继续执行了
情景二:main线程调用t1.join(1000)
当millis等于1000时,进入②处的else语句,同样循环去判断t1线程是否存活,存活的话先计算还需要等待的时间delay,如果delay<0就跳出循环;如果delay>0,就继续进行等待,然后更新当前已经等待的时间now。
所以当t1执行完或者等待的时间结束main线程都会继续执行不再继续等待。
注意到
join(long millis)方法前面有synchronized,所以可以调用wait方法。如果两个线程都调用
t1.join(),有一个线程就会因为获取不到锁进行阻塞。
面试题分享
wait和sleep有什么区别?
wait和sleep方法都能够使当前线程进行等待,区别主要有以下几点
wait方法必须在获取锁之后调用,sleep方法可以在任何地方调用;wait方法会释放锁,让出CPU的执行权;sleep不会让出CPU的执行权;- 调用
wait方会使线程进入WAITIING状态,sleep方法使线程进入TIMED_WAITING状态; - 正因为
wait方法需要加锁,而加锁针对的是对象,所以wait方法定义在了Object中;而sleep不需要加锁,只针对当前线程,所以定义在了Thread类中。
能力一般,水平有限,不足之处还望指正,我会好好改的