【代码下载】
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