一、相关知识简介
在生产者-消费者模型中,若只使用synchronized关键字实现对象锁,程序在运行中可能会出现以下两种情况:
- 若生产者的速度大于消费者,那么在消费者来不及取前一个数据之前,生产者又产生了新的数据,于是消费者很可能会跳过前一个数据。
-
若消费者的速度大于生产者,那么消费者可能多次取同一个数据。
为了避免上述情况,必须使生产者向object对象中存储数据与消费者从object对象中取走数据同步起来。因此,在程序中可以采用信号量模型,同时通过调用对象的wait方法和notifyAll方法来实现同步。
信号量模型的工作方式:线程在运行的过程中,可以主动停下来,等待某个信号量的通知,此时该线程就进入到该信号量的等待队列中,直到得到通知后,再继续运行。在Java语言中,Object对象的wait方法就是等待通知,notify或notifyAll方法就是发出通知,唤醒在该信号量的等待队列里面的相关线程。
二、生产者-消费者模型的案例
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();
}
}