本文参考《Java并发编程的艺术》
何为生产者-消费者模型?
生产者和消费者在同一时间段内共用同一个共享空间,生产者生产商品到共享空间,消费者则消费共享空间的商品,没有商品时消费者阻塞,没有剩余空间存放商品时生产者阻塞。
当然,在没有学习Java并发机制之前我们可以这样处理:
//生产者
while(size==full){ //空间已满
Thread.sleep(1000);
}
produce(); //生产商品
//消费者
while(size==empty){ //空间为空
Thread.sleep(1000);
}
consume(); //消费商品
这样的缺点:
- 及时性难以保证,有1s的等待时间。
- 难以降低开销,避免重复无用请求所以设置睡眠时间,而这样导致及时性下降,睡眠时间缩短会导致cpu无用请求增多,浪费资源,两种情况形成矛盾。
Java的等待通知就解决了这个问题,一个线程调用对象的wait()方法进入等待状态,释放cpu资源(sleep不会释放cpu资源),另一个线程调用该对象的的notify()/notifiyAll()方法,线程收到通知后在wait()方法返回。
用等待通知模型处理生产者-消费者模型。
public class Sample {
static int size=0;
static int full=10;
static int empty=0;
static Object lock=new Object();
public static void main(String[] args) throws InterruptedException {
new Thread(new ConsumerThread()).start();
Thread.sleep(1000);
new Thread(new ProducerThread()).start();
}
static class ConsumerThread implements Runnable{ //消费者线程
@Override
public void run() {
synchronized (lock) {
while (size == empty) {
try {
System.out.println("Consumer wait"); //没有商品,消费者等待
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
size--; //消费商品
lock.notify(); //通知生产者有空余空间
System.out.println("Consumer:"+size);
}
}
}
static class ProducerThread implements Runnable{
@Override
public void run() {
synchronized (lock) {
while (size == full) {
try {
System.out.println("Producer wait"); //剩余空间不足,生产者等待
lock.wait(); //让出cpu资源
} catch (InterruptedException e) {
e.printStackTrace();
}
}
size++; //生产商品
lock.notify(); //通知消费者已有商品
System.out.println("Producer:"+size);
}
}
}
}