从消费者生产者模型理解wait()和notify()的用法
首先要明确的一点是wait()和notify()都是在Object类中定义的方法;
wait()方法:
当一个线程调用一个共享变量的wait()方法时,该线程会被阻塞挂起,知道发生以下事件之一才会返回:
1.其他线程调用该共享变量的notify()(随机唤醒一个挂起的线程),notifyALL()(唤醒该由共享变量wait的全部线程);
2.其他线程调用了该线程的interrupt()方法,该线程抛出InterruptedException异常;
wait() 方法会挂起当前线程,但是会释放当前共享变量的锁。
notify()方法不作过多赘述;
需要注意的是,调用wait()方法和notify()的线程必须事先获得该共享对象的监视器锁,如若不然,则会抛出IllegalMonitorStateException异常;
获取对象锁的方法有两种:
synchronized(共享变量){
共享变量.wait();
}
synchronized void fun(){
共享变量.wait();
}
另外,一个线程可以不用notify直接从被挂起状态变为运行状态,这被称为虚假唤醒
为了避免虚假唤醒,我们通常的写法是下面这样:
synchronized(共享变量){
while(条件) {
共享变量.wait() ;
}
}
下面是一个简单的生产者消费者模型用于理解这两个方法的用法:
public class threadTest_1 {
//“商品”
private static Integer num = 10;
//共享变量,用于加锁
private static final Object obj = new Object();
public static void main(String[] args) {
//生产者线程
Thread thread1 = new Thread(() -> {
while (true){
synchronized (obj) {
//如果“产品”过剩,则阻塞当前进程,并释放锁
while (num == 10) {
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num++;
//唤醒消费者线程
obj.notify();
System.out.println(num);
}
}
}
);
//消费者线程
Thread thread2 = new Thread(() -> {
while (true){
synchronized (obj) {
while (num == 0) {
try {
//如果“产品”无剩余,则阻塞当前进程,并释放锁
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
num--;
//唤醒生产者线程
obj.notify();
System.out.println(num);
}
}
}
);
thread1.start();
thread2.start();
}
}