Java 线程Join

线程上的wait-notify

joinThread的实例方法,效果是等待这个线程结束,谁调用谁等待,即调用线程等待目标线程结束
内部实现基于Wait-Notify机制,会导致调用者wait释放锁进入等待状态,目标线程终结后会调用notifyAll唤醒

Thread.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public final void join() throws InterruptedException {
join(0);
}
//同步方法,wait操作需要获取锁
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;

//...
if (millis == 0) {
while (isAlive()) {
wait(0); //即this.wait()调用线程持有锁进入,一直等待在this线程实例上并放锁,直到被唤醒
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}

测试例子

Sample
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class Worker extends Thread {
private volatile boolean quittingTime = false;

@Override
public void run() {
while (!quittingTime) {
pretendToWork();
}
System.out.println("work ends");
}

private void pretendToWork() {
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
}
System.out.println("work");
}

synchronized void quit() throws InterruptedException {
quittingTime = true;
System.out.println("quit called");
join();
System.out.println("quit ends");
}

synchronized void keepWorking() {
quittingTime = false;
System.out.println("keep working called");
}

public static void main(String[] args) throws InterruptedException {
//工作线程启动
final Worker worker = new Worker();
worker.start();

//另一线程5s后设置继续工作
Timer t = new Timer(true); // Daemon thread
t.schedule(new TimerTask() {
@Override
public void run() {
worker.keepWorking();
}
}, 5000);

//4s后主线程拿到锁,设置停止工作
Thread.sleep(4000);
//主线程调用quit内的join,主线程等待
worker.quit();
}
}

quitkeepWorking方法都带有synchronized同步,预想quit方法设置结束标记,并调用的join会等待线程结束
然而join释放了锁,使得还没等到结束时,keepWorking又将标记设回,导致线程无法结束,quit也无法结束

1
2
3
4
5
6
work
quit called
keep working called
work
work
work