1 相关知识简介
在生产者-消费者模型中,若只使用synchronized
关键字实现对象锁,程序在运行中可能会出现以下两种情况:
- 若生产者的速度大于消费者,那么在消费者来不及取前一个数据之前,生产者又产生了新的数据,于是消费者很可能会跳过前一个数据。
- 若消费者的速度大于生产者,那么消费者可能多次取同一个数据。
- 为了避免上述情况,必须使生产者向
object
对象中存储数据与消费者从object
对象中取走数据同步起来。因此,在程序中可以采用信号量模型,同时通过调用对象的wait
方法和notifyAll
方法来实现同步。 - 信号量模型的工作方式:线程在运行的过程中,可以主动停下来,等待某个信号量的通知,此时该线程就进入到该信号量的等待队列中,直到得到通知后,再继续运行。在
Java
语言中,Object
对象的wait
方法就是等待通知,notify
或notifyAll
方法就是发出通知,唤醒在该信号量的等待队列里面的相关线程。
2 生产者-消费者模型的案例
package JavaPrograms;
/*
* 该类的对象为共享资源
* 新增信号量available:当为true时,表示数据已经产生但还没被取走;
* 当为false时,表示数据已经被取走但还没有存放新的数据。
*/
class MyData2{
private int content;
private boolean available=false;
public synchronized void put(int value){
while(available==true){
try{
wait();
}catch(InterruptedException e){
}
}
this.content=value;
available=true;
notifyAll();
}
public synchronized int get(){
while(available==false){
try{
wait();
}catch(InterruptedException e){
}
}
available=false;
notifyAll();
return this.content;
}
}
/*
* 生产者
*/
class Producer2 extends Thread{
private MyData2 data;
public Producer2(MyData2 data){
this.data=data;
}
public void run(){
for(int i=1;i<=5;i++){
this.data.put(i);
System.out.println("生产者:生成物品,编号为:"+i);
try{
sleep((int)(Math.random()*100));
}catch(InterruptedException e){
}
}
}
}
/*
* 消费者
*/
class Consumer2 extends Thread{
private MyData2 data;
public Consumer2(MyData2 data){
this.data=data;
}
public void run(){
int value=0;
for(int i=1;i<=5;i++){
value=this.data.get();
System.out.println("消费者:消费物品,编号为:"+value);
}
}
}
public class ProducerAndConsumer2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyData2 md=new MyData2();
Producer2 p=new Producer2(md);
Consumer2 c=new Consumer2(md);
p.start();
c.start();
}
}