Wait() 与 Notify()
Wait()
与Notify()
常出现在多线程编程中,当线程想保留资源且希望线程能够随时重获资源时,就需要使用这两个函数。
class TaskQueue {
Queue<String> queue = new LinkedList<>();
public synchronized void addTask(String s) {
this.queue.add(s);
}
public synchronized String getTask() {
while (queue.isEmpty()) {
}
return queue.remove();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
上面这段代码中,当我们调用addTask()
时,能为队列添加元素,由于该方法声明了synchronized
,因此会将资源上锁。而当我们调用getTask()
时,会检测队列是否为空,如果为空就陷入while循环,否则获取元素。
我们希望该组函数实现的功能是:
- 如果队列不为空,则返回元素
- 如果队列为空,则陷入while循环等待其他线程调用
addTask()
,然后再返回新的元素出去。
但事实并不如我们所料,当队列为空时,getTask()
会卡在while循环,无法释放锁。这意味着其他人也无法调用addTask()
去添加元素。
那么有没有一种方法能让getTask()
暂时释放锁,等添加元素后再重新获取锁呢?
那就需要依靠Wait()
与Notify()
了。
class TaskQueue {
Queue<String> queue = new LinkedList<>();
public synchronized void addTask(String s) {
this.queue.add(s);
this.notify(); //唤醒wait();
}
public synchronized String getTask() {
while (queue.isEmpty()) {
this.wait(); // 暂时释放锁
}
return queue.remove();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
我们为addTask()
和getTask()
分别调用了Wait()
与Notify()
,这样,当队列为空时,会暂时放弃锁,等其他人调用addTask()
时,会唤醒他,并继续任务。
# 注意
Notify()
是随机唤醒一个wait()
,这里更加推荐使用notifyAll()
,该方法能够唤醒所有wait()
,这函数更加安全,避免了[[线程饥饿]]