更多 Java 并发编程方面的文章,请参见文集《Java 并发编程》
wait 和 notify 的功能
-
obj.wait():
- 如果当前调用 obj.wait() 的线程并没有获得该对象 obj 上的锁,则抛出异常 IllegalMonitorStateException
- 否则,当前线程进入 Waiting Pool 状态
- 线程调用 obj.wait() 方法后,在如下条件下,会从 Waiting Pool 状态进入 Waiting for monitor entry 状态:
- 该对象的 notify() 方法被调用
- 该对象的 notifyAll() 方法被调用
- obj.wait() 可以添加参数,例如 obj.wait(1000),表示 1000 毫秒后自动进入 Waiting for monitor entry 状态
- 线程被中断
-
obj.notify():唤醒 一个 正在 Waiting Pool 中等待该对象的线程进入 Waiting for monitor entry 状态
- 具体是唤醒哪一个?与优先级无关,由 JVM 决定
obj.notifyAll():唤醒 所有 正在 Waiting Pool 中等待该对象的线程进入 Waiting for monitor entry 状态
线程进入 Waiting for monitor entry 状态后,一旦该对象被解锁,这些线程就会去竞争。
wait 和 notify 的使用
- wait, notify, notifyAll 方法需要放在 synchronized 代码块中,因为必须先获得对象的锁!
- 由于线程可能在非正常情况下被意外唤醒,一般需要把 wait 方法放在一个循环中,例如:
synchronized(obj) {
while(some condition) {
try {
obj.wait();
} catch(...) {...}
}
}
通过wait和notify实现生产者消费者模式
代码如下:
public class ProducerCunsumer_Test {
private static final int MAX_CAPACITY = 10;
private static List<Object> goods = new ArrayList<Object>();
public static void main(String[] args) {
(new ProducerThread()).start();
(new ConsumerThread()).start();
}
static class ProducerThread extends Thread {
public void run() {
while (true) {
// 每隔 1000 毫秒生产一个商品
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
synchronized (goods) {
// 当前商品满了,生产者等待
if (goods.size() == MAX_CAPACITY) {
try {
System.out.println("Goods full, waiting...");
goods.wait();
} catch (Exception e) {
}
}
goods.add(new Object());
System.out.println("Produce goods, total: " + goods.size());
// goods.notify() 也可以
goods.notifyAll();
}
}
}
}
static class ConsumerThread extends Thread {
public void run() {
while (true) {
// 每隔 500 毫秒消费一个商品
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
synchronized (goods) {
// 当前商品空了,消费者等待
if (goods.size() == 0) {
try {
System.out.println("No goods, waiting...");
goods.wait();
} catch (Exception e) {
}
}
goods.remove(0);
System.out.println("Consume goods, total: " + goods.size());
// goods.notify() 也可以
goods.notifyAll();
}
}
}
}
}
在上面的代码中,消费商品的速度(500毫秒)快于生产商品的速度(1000毫秒),依次输出如下所示:
可以看出,商品队列经常处于空的状态。
No goods, waiting...
Produce goods, total: 1
Consume goods, total: 0
No goods, waiting...
Produce goods, total: 1
Consume goods, total: 0
No goods, waiting...
Produce goods, total: 1
Consume goods, total: 0
如果修改,使得消费商品的速度(500毫秒)慢于生产商品的速度(100毫秒),依次输出如下所示:
可以看出,商品队列经常处于满的状态。
Produce goods, total: 1
Produce goods, total: 2
Produce goods, total: 3
Produce goods, total: 4
Produce goods, total: 5
Consume goods, total: 4
Produce goods, total: 5
Produce goods, total: 6
Produce goods, total: 7
Produce goods, total: 8
Consume goods, total: 7
Produce goods, total: 8
Produce goods, total: 9
Produce goods, total: 10
Goods full, waiting...
Consume goods, total: 9
Produce goods, total: 10
Goods full, waiting...
Consume goods, total: 9
Produce goods, total: 10
Goods full, waiting...
Consume goods, total: 9
Produce goods, total: 10
Goods full, waiting...