【经典问题】生产者消费者

来源:互联网 发布:windows主题包 编辑:程序博客网 时间:2024/06/15 06:03

生产者消费者问题是线程同步的经典问题,其中的逻辑和细节是很多初学者犯错的地方,博主今日就此问题进行了一下回顾。

背景:生产者->厨师(蒸馒头,最多20个) 消费者->顾客(吃馒头,最多20个)  篮子里最多装6个,这里就涉及到了线程同步问题。


public class ProducerConsumer {    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;    public ManTou(int id) {        this.id = id;    }    public String toString(){        return "馒头"+id;    }}class SyncStack{    int index = 0;    ManTou[] arrMT = new ManTou[6];    public synchronized void push(ManTou mt){        while (index == arrMT.length) {   //这里不用if的原因是下面的try语句catch到异常会继续向下执行  index会越界!!!            try {                this.wait();            } catch (InterruptedException ex) {  //  看这里!!!                ex.printStackTrace();                 }        }                this.notifyAll(); //这里可以配合多个线程        arrMT[index] = mt;        index++;        System.out.println("篮子里面有"+index+"个");    }        public synchronized ManTou pop(){        while (index == 0) {           //同不用if  用while            try {                this.wait();            } catch (InterruptedException ex) {                ex.printStackTrace();            }        }                this.notifyAll();        index--;        return arrMT[index];    }}class Producer implements Runnable{    SyncStack ss = null;    public Producer(SyncStack ss) {        this.ss = ss;    }        public void run() {        for (int i = 0; i < 20; i++) {            ManTou mt = new ManTou(i);            System.out.print("生产了" + mt+",");            ss.push(mt);            try {                Thread.sleep((int)(Math.random()*100));            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}class Consumer implements Runnable{    SyncStack ss = null;    public Consumer(SyncStack ss) {        this.ss = ss;    }        public void run() {        for (int i = 0; i < 20; i++) {            ManTou mt = ss.pop();   ///这里我曾经错了   曾经这么写的  ManTou = new Mantou(i);ss.pop(mt); 错了!!!记住!!!            System.out.println("消费了" + mt+",吃了 "+(i+1)+" 个"+",还有"+ss.index+"个");            try {                Thread.sleep((int)(Math.random()*100));            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}

里面注释也写得比较详细,

ps:最开始遇到很恶心的问题,就是有时候会出现先消费的情况,明明篮子里面没有馒头,但是还是先消费了,然后我也没找到问题的所在,但是后来没管它,竟然又没有问题了。如果这个问题还在发生着并且你找到了问题的所在,请及时联系我,谢谢。

0 0