java模拟生产者与消费者问题(线程同步)

关于生产者与消费者的问题,百度百科上的定义是这样的:生产者消费者问题,也称有限缓冲问题,是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

今天在学习java时遇到这个问题,以一个具体的例子来看这个问题:有生产者生产馒头,消费者在吃馒头,一个放馒头的篮子,生产者和消费者就相当于两个线程,篮子相当于缓冲区;用java模拟这个问题,需要定义两个线程类Producer和Consumer,以及一个栈的类SyncStack,栈相当于篮子;生产者做好馒头放进篮子里,消费者从篮子里面拿馒头,具体代码如下:


public class ProducerConsumer {
  /**
 * @param args
 * 主函数,测试代码
 * 一个生产者,一个消费者,栈数组容量为6
 */
public static void main(String[] args) {
    SyncStack ss=new SyncStack();
    Producer p=new Producer(ss);
    Consumer c=new Consumer(ss);
    new Thread(p).start();
    new Thread(c).start();
  }
}

class ManTou {
  int id;
  ManTou(int id) {
    this.id=id;//生产的每个馒头给一个id
  }
  public String toString() {
    return "Mantou:"+id;
  }
}
/*定义一个栈模拟缓冲区*/
class SyncStack {
  int index=0;//栈中剩余元素个数,地址值
  ManTou[] arrMT=new ManTou[6];//馒头类型的数组,容量为6
  /**
 * @param mt
 * push定义为synchronized类型的,避免mt的产生和地址的增加不同步
 */
public synchronized void push(ManTou mt) {
    while(index==arrMT.length) {//当栈满时,进入wait等待
      try {
        this.wait();
      } catch(InterruptedException e) {
        e.printStackTrace();
      }
    }
    this.notify();//唤醒当前进程
    arrMT[index]=mt;
    index++;
    System.out.println("剩余个数:" +index);
  }
  /**
 * @return arrMT[index]
 * pop方法同样为synchronized类型
 */
public synchronized ManTou pop() {
    while(index==0) {
      try {
        this.wait();
      } catch(InterruptedException e) {
        e.printStackTrace();
      }
    }
    this.notify();
    index--;
    System.out.println("剩余个数:" +index);
    return arrMT[index];
  }
}
//生产者的线程类
class Producer implements Runnable{
  SyncStack ss=null;
  Producer(SyncStack ss) {
    this.ss=ss;
  }
  public void run() {
    for(int i=0;i<10;i++) {
      ManTou mt=new ManTou(i);
      ss.push(mt);
      System.out.println("生产了"+mt);
      try {
        Thread.sleep(1000);//每生产一次sleep 1 s
      } catch(InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}
//消费者的线程类
class Consumer implements Runnable{
  SyncStack ss=null;
  Consumer(SyncStack ss) {
    this.ss=ss;
  }
  public void run() {
    for(int i=0;i<10;i++) {
      ManTou mt=new ManTou(i);
      ss.pop();
      System.out.println("消费了"+mt);
      try {
        Thread.sleep(3000);//每消费一次sleep 3 s
      } catch(InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

运行结果:



生产和消费的个数都是10,当生产满6个时将不再生产(栈满),等到消费者消费后又会生产。

你可能感兴趣的:(学习笔记)