java生产消费问题

编写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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值