join是Thread類下的實例方法,其核心思想是:在誰的業務代碼裏調用,誰就等待!
舉個例子:
public class JoinThread implements Runnable {
private final Object lock = new Object();
@Override
public void run() {
String name = Thread.currentThread().getName();
String state = Thread.currentThread().getState().toString();
System.out.println(name + ":" + state);
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " .....................begin.");
try {
// Thread.sleep(3000); // 不讓CPU,不釋放鎖
Thread.currentThread().join(3000); // 讓出CPU,釋放當前線程的對象鎖,但不釋放lock鎖
// lock.wait(3000); // 讓出CPU,釋放鎖
System.out.println(Thread.currentThread().getName() + " .....................end.");
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TestJoin {
public static void main(String[] args) {
Runnable r = new JoinThread();
Thread t1 = new Thread(r);
t1.setName("Thread1");
t1.start();
Thread t2 = new Thread(r);
t2.setName("Thread2");
t2.start();
}
}
執行結果:
Thread1:RUNNABLE
Thread1 .....................begin.
Thread2:RUNNABLE
Thread1 .....................end.
Thread2 .....................begin.
Thread2 .....................end.
可見,鎖是不釋放的,但是看join源代碼,會發現,其實現等待的原理是調用wait,我們知道wait方法是釋放鎖的,但爲啥上面例子卻沒有釋放鎖呢?其實很簡單,join方法是被synchronized修飾的,它本質上是一個對象鎖,也就是說,join方法本身會加鎖,其內部的wait方法調用也是釋放鎖的,但是它釋放的是當前線程的對象鎖,而不是外面的lock鎖。
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;
}
}
}