JAVA同步-生产者与消费者实现 二
生产者消费者模型:
实现手段:LinkedBlockingQueue(阻塞队列)实现; //LinkedBlockingQueue:底层为链表实现的队列位于
java.lang.Object-->java.util.AbstractCollection<E>-->java.util.AbstractQueue<E>--> java.util.concurrent.LinkedBlockingQueue.
问题描述:吃吐司蛋糕,吐司蛋糕状态:1.面包状态。2.抹酱状态。 3.制作完成状态(待吃态)。4.食用(吃货)。
队列使用过程:可以分别生成 1.制作吐司队列 ,2.抹黄油队列 ,3.涂果酱队列 ,4.吃吐司队列。
图示:
吐司类:
class Toast1{ // 吐司的状态 public enum Status{ DRY, BUTTERED, JAMMED; } public final int Id; private Status status=null; //初始当前的吐司 Toast1(int Id){ this.Id=Id; this.status=Status.DRY; } //得到当前吐司编号 public int getId() { return Id; } //得到当前吐司状态 public Status status(){ return this.status; } //通过状态来判断吐司的位于哪个队列:状态的转换; //第一步转换 public void FirstChange(){ this.status=Status.BUTTERED; } //第二步转换 public void SecondChange(){ this.status=Status.JAMMED; } @Override public String toString() { return "第" + this.Id + "个吐司,状态是:" + this.status; } }
队列实现:用LinkedBlockingQueu阻塞队列类,实现Toast1Queue吐司队列类;
//注也可以不用实现此队列,直接放不同的阻塞队列种。但是这样做思路逻辑不清晰;
//简单的覆写,可以让思路逻辑清晰; class Toast1Queue extends LinkedBlockingQueue<Toast1> { private static final long serialVersionUID = 1L; }
制作吐司第一步:做面包
class FirstToast1 implements Runnable { // 持有吐司第一个状态队列 private Toast1Queue queue1; // 吐司制作的编号 private int cnt = 0; FirstToast1(Toast1Queue queue) { this.queue1 = queue; } public void run() { try { while (!Thread.interrupted()) { // 生成面包 Toast1 t = null; if (++cnt < 11) { // 默认生成面包所以不需要更改状态; t = new Toast1(cnt); } if (t != null) { // 查看状态 System.out.println(t); // 放入第一个队列中; this.queue1.add(t); } TimeUnit.MILLISECONDS.sleep(1); } } catch (InterruptedException e) { System.out.println("第一步终断线程!"); // e.printStackTrace(); } } }
制作吐司第二步:抹酱
class SecondToast1 implements Runnable { private Toast1Queue queue1, queue2; // 线程需要: 队列1,拿出面包。队列2,放入涂酱面包; SecondToast1(Toast1Queue queue1, Toast1Queue queue2) { this.queue1 = queue1; this.queue2 = queue2; } public void run() { try { while (!Thread.interrupted()) { // 得到状态1 Toast1 t = this.queue1.take(); // 抹黄油 if (t.getstatus() == Toast1.Status.DRY) { t.FirstChange(); } if (t != null) { // 查看状态 System.out.println(t); // 放入队列2 queue2.add(t); } TimeUnit.MICROSECONDS.sleep(1000); } } catch (InterruptedException e) { System.out.println("第二步终断线程!"); // e.printStackTrace(); } } }
制作吐司第三步:加工完成
class ThirdlyToast1 implements Runnable { private Toast1Queue queue2, queue3; // 线程需要: 队列2,拿出涂酱面包。队列3,放入待吃面包; ThirdlyToast1(Toast1Queue queue2, Toast1Queue queue3) { this.queue2 = queue2; this.queue3 = queue3; } public void run() { try { while (!Thread.interrupted()) { // 得到状态2 Toast1 t = this.queue2.take(); // 加工待食用 if (t.getstatus() == Toast1.Status.BUTTERED) { t.SecondChange(); ; } if (t != null) { // 查看状态 System.out.println(t); // 放入队列3 queue3.add(t); } TimeUnit.MICROSECONDS.sleep(1000); } } catch (InterruptedException e) { System.out.println("第三步终断线程!"); // e.printStackTrace(); } } }
制作吐司完成:食用
class Eat implements Runnable { private Toast1Queue queue3; int cont = 0; // 线程需要: 队列3,拿出待食用。 Eat(Toast1Queue queue3) { this.queue3 = queue3; } public void run() { try { while (!Thread.interrupted()) { // 得到状态3. Toast1 t = this.queue3.take(); // 判断信息是否正确:吃的对不对 if (t.getstatus() == Toast1.Status.JAMMED && t.getId() == (++cont)) { System.out.println("食用第" + t.getId() + "完成!"); } // else 保证正常退出;最后(第11个)放的是一个NULL else { // System.exit(1); } TimeUnit.MICROSECONDS.sleep(1000); } } catch (InterruptedException e) { System.out.println("第四步终断线程!"); // e.printStackTrace(); } } }
线程启动:
public class TestToast1 { public static void main(String[] args) throws InterruptedException { Toast1Queue queue1 = new Toast1Queue(); Toast1Queue queue2 = new Toast1Queue(); Toast1Queue queue3 = new Toast1Queue(); ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(new FirstToast1(queue1)); exec.execute(new SecondToast1(queue1, queue2)); exec.execute(new ThirdlyToast1(queue2, queue3)); exec.execute(new Eat(queue3)); TimeUnit.SECONDS.sleep(5); exec.shutdownNow(); } }
运行结果: