java生产消费问题

来源:互联网 发布:ubuntu如何重置系统 编辑:程序博客网 时间:2024/04/30 13:55

编写SynStack类

最基础的想法如下:Consumer类和Producer类实现Runnable接口,run方法中调用push与pop

    public class SynStack {    private char[] data = new char[6];    private int cnt=0;    public  void push(char ch){        data[cnt]=ch;        cnt++;        System.out.println("生产线程,生产第"+cnt+"个产品,此产品是"+ch);    }    public  char pop(){        char ch=data[cnt-1];        System.out.println("消费线程,消费第"+cnt+"个产品,此产品是"+ch);        --cnt;        return ch;    }}

问题:无法控制消费与生产哪个先执行,若消费先执行,data[-1]越界,报错,故必须对满或空加以判断,空则无法消费,满则无法继续生产.

加以改进,完整代码如下

public class SynStack {    private char[] data = new char[6];    private int cnt=0;    public synchronized void push(char ch){        while(cnt == data.length){            try {                this.wait();            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }        this.notify();        data[cnt]=ch;        cnt++;        System.out.println("生产线程,生产第"+cnt+"个产品,此产品是"+ch);    }    public synchronized char pop(){        while(cnt == 0){            try {                this.wait();            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }        this.notify();        char ch=data[cnt-1];        System.out.println("消费线程,消费第"+cnt+"个产品,此产品是"+ch);        --cnt;        return ch;    }}
public class Producer implements Runnable{    private SynStack ss =null;    public Producer(SynStack ss){        this.ss = ss;    }    @Override    public void run() {        // TODO Auto-generated method stub        char ch;        for(int i=0;i<20;++i){        ch =(char)('a'+i);        ss.push(ch);        /*try {            Thread.sleep(1000);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }*/        }    }}
public class Consumer implements Runnable{    private SynStack ss = null;    public Consumer(SynStack ss){        this.ss = ss;    }    @Override    public void run() {        // TODO Auto-generated method stub        for(int i=0;i<20;++i){        ss.pop();        }    }}
public class Consumer implements Runnable{    private SynStack ss = null;    public Consumer(SynStack ss){        this.ss = ss;    }    @Override    public void run() {        // TODO Auto-generated method stub        for(int i=0;i<20;++i){        ss.pop();        }    }}

解释:

  1. synchronized修饰方法,表示当前线程霸占正在调用该方法的对象(本例中即SynStack的实例ss)。即生产线程执行push时,会先判断ss是否被消费线程霸占,若没有,则生产线程霸占ss,执行push。从而保证了在执行push操作时,不会切到消费线程去执行
  2. wait与notify:aa.wait()表示将执行aa.wait()的线程阻塞,并释放对aa的锁定。若有T1,T2两个线程,T1由于执行过aa.wait()而阻塞,当T2中执行aa.notify()时,即将T1线程唤醒,转为就绪态

运行结果

生产线程,生产第1个产品,此产品是a生产线程,生产第2个产品,此产品是b生产线程,生产第3个产品,此产品是c生产线程,生产第4个产品,此产品是d生产线程,生产第5个产品,此产品是e生产线程,生产第6个产品,此产品是f消费线程,消费第6个产品,此产品是f生产线程,生产第6个产品,此产品是g消费线程,消费第6个产品,此产品是g生产线程,生产第6个产品,此产品是h消费线程,消费第6个产品,此产品是h生产线程,生产第6个产品,此产品是i消费线程,消费第6个产品,此产品是i生产线程,生产第6个产品,此产品是j消费线程,消费第6个产品,此产品是j生产线程,生产第6个产品,此产品是k消费线程,消费第6个产品,此产品是k生产线程,生产第6个产品,此产品是l消费线程,消费第6个产品,此产品是l生产线程,生产第6个产品,此产品是m消费线程,消费第6个产品,此产品是m生产线程,生产第6个产品,此产品是n消费线程,消费第6个产品,此产品是n生产线程,生产第6个产品,此产品是o消费线程,消费第6个产品,此产品是o生产线程,生产第6个产品,此产品是p消费线程,消费第6个产品,此产品是p生产线程,生产第6个产品,此产品是q消费线程,消费第6个产品,此产品是q生产线程,生产第6个产品,此产品是r消费线程,消费第6个产品,此产品是r生产线程,生产第6个产品,此产品是s消费线程,消费第6个产品,此产品是s生产线程,生产第6个产品,此产品是t消费线程,消费第6个产品,此产品是t消费线程,消费第5个产品,此产品是e消费线程,消费第4个产品,此产品是d消费线程,消费第3个产品,此产品是c消费线程,消费第2个产品,此产品是b消费线程,消费第1个产品,此产品是a

还存在问题吗?

  1. 代码中生产20次,消费20次,程序可以正常结束。若不匹配,程序会停住,无法正常结束,也不会继续成产与消费。当然,可以将run()中pop与push放在死循环里,不停的生产与消费。
  2. pop()与push()中对空和满的判断一定要用while吗,换成if判断不行吗?我的主函数中就一个生产者,一个消费者,运行没有问题。若有多个生产者,多个消费者时,必须用while。我用1个生产者,2个消费者测试,提示-1数组越界,详细请看如何在 Java 中正确使用 wait, notify 和 notifyAll
0 0
原创粉丝点击