【java线程】生成有限生产,且待消费者消费完全部消息后,生产者消费者相继退出的现实模式

【代码下载】

https://files.cnblogs.com/files/heyang78/real_comsumerproducer20220714.rar?t=1657804074

【书写初衷】

甚多教程写消费者生产者模式,都是while(true)无限循环,没有一个退出机制,并不符合实际情况。

为此我书写了一个新模式,让生成有限生产,且待消费者消费完全部消息后,生产者消费者相继退出。

这种模式比较适合有限数据的场合。

生产者最后给消费者发确定的离开消息是关键一步。

【代码】

队列类: 

package com.hy.lab.comsumerproducer;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Queue<T>{
    private BlockingQueue<T> queue;

    private int limit;

    public Queue(int limit){
        this.limit=limit;
        queue=new ArrayBlockingQueue<>(limit);
    }

    public synchronized void put(T data) throws InterruptedException{
        while(queue.size()==limit){ // 此处while/if皆可
            wait();
        }

        queue.add(data);
        this.notifyAll();
    }

    public synchronized T take() throws InterruptedException{
        while(queue.isEmpty()){ // 此处while/if皆可
            wait();
        }

        T data=queue.poll();
        this.notifyAll();

        return data;
    }

    public void tellComsumerLeave(){
        //this.notify();
    }
}

 

生产者类:

 

package com.hy.lab.comsumerproducer;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class Producer extends Thread{
    Queue<String> queue;
    int msgCnt;
    CountDownLatch cdl;

    public Producer(Queue<String> queue,int msgCnt,CountDownLatch cdl){
        this.queue=queue;
        this.msgCnt=msgCnt;
        this.cdl=cdl;
    }

    public void run(){
        try {
            int i = 0;
            while (i < msgCnt) {
                String msg="消息:" + i + ".";
                System.out.println("生产者制成"+msg);
                queue.put(msg);
                i++;
            }

            cdl.await(10, TimeUnit.SECONDS);
            queue.put("LEAVE");// 最后发一个确定的标志离开的消息将wait的comsumer解救出来
            System.out.println("生产者退出");
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

 

消费者类:

 

package com.hy.lab.comsumerproducer;

import java.util.concurrent.CountDownLatch;

public class Comsumer extends Thread{
    Queue<String> queue;
    Producer producer;
    CountDownLatch cdl;

    public Comsumer(Queue<String> queue,Producer producer,CountDownLatch cdl){
        this.queue=queue;
        this.producer=producer;
        this.cdl=cdl;
    }

    public void run(){
        try {
            while (true) {
                String msg=queue.take();
                if(msg.equalsIgnoreCase("LEAVE")==false) {
                    System.out.println("   消费者取得" + msg);
                    cdl.countDown();
                }else{
                    break;
                }
            }

            System.out.println("   消费者离开");
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

 

测试类: 

package com.hy.lab.comsumerproducer;

import java.util.concurrent.CountDownLatch;

public class Test {
    public static void main(String[] args){
        Queue<String> queue=new Queue<>(5);

        final int msgCnt=10;
        CountDownLatch cdl=new CountDownLatch(msgCnt);

        Producer producer=new Producer(queue,msgCnt,cdl);
        producer.start();

        Comsumer comsumer=new Comsumer(queue,producer,cdl);
        comsumer.start();
    }
}

 

【输出】

生产者制成消息:0.
生产者制成消息:1.
生产者制成消息:2.
生产者制成消息:3.
生产者制成消息:4.
生产者制成消息:5.
生产者制成消息:6.
   消费者取得消息:0.
生产者制成消息:7.
   消费者取得消息:1.
生产者制成消息:8.
   消费者取得消息:2.
   消费者取得消息:3.
生产者制成消息:9.
   消费者取得消息:4.
   消费者取得消息:5.
   消费者取得消息:6.
   消费者取得消息:7.
   消费者取得消息:8.
   消费者取得消息:9.
生产者退出
   消费者离开

Process finished with exit code 0
缩进使得消费者代码和生产者代码输出更清晰。

 【参考资料】

《Java编程的逻辑》马俊昌著 机械工业出版社出版 P453页

原例子是基于生产者消费者无限循环,缺乏退出机制。本人已经让原作升华了。

END

posted @ 2022-07-14 20:01  逆火狂飙  阅读(67)  评论(1编辑  收藏  举报
生当作人杰 死亦为鬼雄 至今思项羽 不肯过江东