在第一篇文章中说过Java的并发模型是共享内存,所以线程间的通信也是基于这个原理实现的,在Java中,使用wait/notify/notifyAll是实现线程间通信的一种简单方式。
我们看下这三个方法的说明(在Object中定义)
通过说明我们看出,wait会导致当前线程进行等待,直到另外一个线程调用notify()、notifyAll()或者等待一个确定的时间过后才会停止等待状态。而notify方法的说明更加精准,它会唤醒在这个对象监视器上进行等待的单个线程。
OK,通过api的说明,我们其实就已经明白了他们的意义。需要注意的是:
1:这些线程必须与某一个对象监视器进行绑定使用,某则notify不知道去通知谁,会报异常。
2:调用wait的时候,它会释放掉对象的锁,不然的话,notify通知还有意思吗?
3:在调用wait方法时,它会抛出一个InterruptedException,条件是
if any thread interrupted the current thread before or while the current thread was waiting for a notification. The interrupted status of the current thread is cleared when this exception is thrown.就是说,如果当前线程在等待wait的时候被其它线程给中断掉了,它就会抛出这个异常,并且它的中断标志会被清除,这个到以后说。
好了,看完api说明一切都明白了。我们只要有一个对象锁就可以很方便的实现线程间的通信了,关于线程锁的问题,请参考上一篇文章。
eg:
public class WaitAndNotifyTest {
public static void main(String[] args) {
Product product = new Product();
product.setCount(1);
//
Thread producerThread = new Thread(new Producer(product));
Thread customerThread = new Thread(new Customer(product));
producerThread.start();
customerThread.start();
}
}
class Product {
private int count;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
class Producer implements Runnable {
private Product product;
public Producer(Product product) {
this.product = product;
}
@Override
public void run() {
synchronized (product) {
for (int i = 0; i < 10; i++) {
while (product.getCount() == 1) {
try {
product.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("生产了一个产品");
product.setCount(1);
product.notify();
}
}
}
}
class Customer implements Runnable {
private Product product;
public Customer(Product product) {
this.product = product;
}
@Override
public void run() {
synchronized (product) {
for (int i = 0; i < 10; i++) {
while (product.getCount() == 0) {
try {
product.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费了一个产品");
product.setCount(0);
product.notify();
}
}
}
}
上述代码的输出结果为:
消费了一个产品
生产了一个产品
消费了一个产品
生产了一个产品
消费了一个产品
生产了一个产品
消费了一个产品
生产了一个产品
消费了一个产品
生产了一个产品
消费了一个产品
生产了一个产品
消费了一个产品
生产了一个产品
消费了一个产品
生产了一个产品
消费了一个产品
生产了一个产品
消费了一个产品
生产了一个产品
OK,总体来说,使用wait和notify还是比较简单的。它们是定义在Object上的方法,任何
对象都有,而且它必须在获得锁的情况下使用,如果在执行过程中它被任何其它线程中断,它会抛出
InterruptedException异常。
在api说明中,它给我们提供了一个比较特殊的情况,即线程有可能在没有被通知、中断或者时间超期等情况下被唤醒,因此,在判断condition是否满足情况时,我们应该使用while而不是if。
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}