一个简单的生产者与消费者的多线程例子(二):不让消费者或生产者无限期地等待

在《一个简单的生产者与消费者的多线程例子(一)》给出了两种具备雏形的生产者与消费者的多线程模式。但是在运行过程中,有一个问题:算法不会自动停止,即使没有products了,consumer还会一直无限期地Wait下去。因此,需要解决阻止消费者无限期地等待的问题。

问题解决思路:当生产者不再生产时,利用一个状态变量通知channel,消费者检测这个状态变量,当发现生产者不再生产后,且channel中没有products了,就return(不要用System.exit(m),因为这会把其他的运行也都终止掉!)。

分析:因为这个状态变量要同时被生产者和使用者使用,因此,放到channel中。

设置:取这个变量为:boolean produceOff,当值为false时表示生产者还在生产,否则生产者停止生产了。

代码工作:
- 修改channel中的take()方法,加入count和produceOff的联合状态判断;
- 修改consumer的consum()方法,加入produceOff的状态判断;
- 修改producer的produce()方法,使其生产有限个products
- 构建一个market,管理对应的channel,producer和consumer

代码如下:
Channel

public class MyChannel4ThreadStop implements MyChannel{

    private final MyProduct[] queue;
    private int tail, head, count;
    private boolean produceOff = false;

    public MyChannel4ThreadStop(int size1) {
        queue = new MyProduct[size1];
        this.head = 0;
        this.tail = 0;
        this.count = 0;
    }

    @Override
    public synchronized void put(MyProduct e) {
        try {
            while (count >= queue.length) {
                wait();
                //System.out.println(Thread.currentThread().getName()+"put() is waiting");
            }
            queue[count] = e;
            tail = (tail + 1) % queue.length;
            count++;
            System.out.println(Thread.currentThread().getName() + "Put in one.Now the number of the products in the channel is:" + count);
            notifyAll();
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }
    }

    @Override
    public synchronized MyProduct take() {//Consumer will stop according to the null return value
        MyProduct e = null;
        try {
            while (count <= 0 && !produceOff) {
                wait();
                //System.out.println(Thread.currentThread().getName()+"take() is waiting!");
            }
            if (count > 0) {
                e = queue[head];
                count--;
                System.out.println(Thread.currentThread().getName() + "Take one out.Now the number of the products in the channel is:" + count);
                notifyAll();
            }else if(produceOff&&count<=0){
                e=null;
            }
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }
        return e;
    }

    /**
     * @param produceOff the produceOff to set
     */
    public void setProduceOff(boolean produceOff) {
        this.produceOff = produceOff;
    }
}

Producer

public class ASimpleProducer4ThreaStop {

 private final MyChannel4ThreadStop pChannel;
    public ASimpleProducer4ThreaStop(MyChannel4ThreadStop pChannel1){
        pChannel=pChannel1;
    }

    public void produce() {
        for (int i = 0;i<50; i++) {
            ASimpleProduct product = new ASimpleProduct("" + i);
            pChannel.put(product);
            try {
                Thread.sleep(i);
            } catch (InterruptedException ex) {
                Logger.getLogger(MyMarketSizeUnlimited.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        pChannel.setProduceOff(true);
    }

}

Consumer

public class ASimpleConsummer4ThreadStop extends MyConsumer{
      public ASimpleConsummer4ThreadStop(MyChannel myChannel1) {
        super(myChannel1);
    }

    @Override
    public void run() {
        try {
            while (true) {
                Thread.sleep(50);
                MyProduct product = myChannel.take();
                if (null == product) {
                    return;
                } else {
                    consum(product);
                }
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(ASimpleConsumer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    protected void consum(MyProduct product) {
    }
}

Market

public class MyMarket4ThreadStop {

    public static void main(String[] args) {
        MyChannel4ThreadStop mychannel = new MyChannel4ThreadStop(20);
        for (int i = 0; i < 5; i++) {
            new Thread(new ASimpleConsummer4ThreadStop(mychannel)).start();
        }
        new ASimpleProducer4ThreaStop(mychannel).produce();
    }
}

上述例子中,生产者不是线程,那么如果生产者也是线程,那么不仅要考虑不让消费者无限期等待,还需要考虑不让生产者无限期等待?这样就要两个问题需要解决。
好消息是,上个例子中解决了第一个问题:不让消费者无限期等待。坏消息是:还需要解决第二个问题:不让生产者无限期等待。

思路:如果生产者是Thread,那么,在produce任务完成后,直接调用自己的interrupt()即可。如果producer是Runnable的implements,那么就需要获得包装它的Thread,而这个Thread在Market中被包装,因此,从Market入手。只需要修改上述例子中Producer和Market的代码即可。

Producer的代码

public class ASimpleProducer4PCstop extends MyProducer {
private Thread thisThread;
    public ASimpleProducer4PCstop(MyChannel myChannel1) {
        super(myChannel1);
    }

    @Override
    public void run() {
        this.make();
    }

    @Override
    protected void make() {
        for (int i = 0; i < 50; i++) {
            ASimpleProduct product = new ASimpleProduct("" + i);
            this.myChannel.put(product);
            try {
                Thread.sleep(i);
            } catch (InterruptedException ex) {
                Logger.getLogger(ASimpleProducer4PCstop.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        ((MyChannel4ThreadStop) myChannel).setProduceOff(true);
        System.out.println("The interrupt will be called!");
        thisThread.interrupt();
    }

    /**
     * @param thisThread the thisThread to set
     */
    public void setThisThread(Thread thisThread) {
        this.thisThread = thisThread;
    }

}

Market的代码

public class MyMarket4ConsumerProducerStop {

    public static void main(String[] args) {
        MyChannel4ThreadStop mychannel = new MyChannel4ThreadStop(20);
        for (int i = 0; i < 5; i++) {
            new Thread(new ASimpleConsummer4ThreadStop(mychannel)).start();
        }
        for (int i = 0; i < 5; i++) {
            ASimpleProducer4PCstop asppc = new ASimpleProducer4PCstop(mychannel);
            Thread t = new Thread(asppc);
            t.start();
            asppc.setThisThread(t);
        }
    }
}

注意到,market代码中把包装producer的Runnable的Thread传递给了producer,供他自己停止自己。

上述两个例子有一个假设是:程序结束的权限在生产者,即当生产者不再生产时,发一个状态变量给channel,消费者根据这个状态变量的值结束程序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值