TIJ -- 吐司BlockingQueue
1. 吐司BlockingQueue
考虑下面这个使用BlockingQueue的示例。有一台机器具有三个任务:一个制作吐司,一个给吐司抹黄油,另一个在抹过黄油的吐司上吐果酱。我们可以通过各个处理过程之间的BlockingQueue来运行这个吐司制作程序:
2. class :
package lime.thinkingInJava._021._005._004; import com.sun.corba.se.impl.oa.toa.TOA; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; /** * @Author : Lime * @Description : * @Remark : */ class Toast{ public enum Status{DRY,BUTTERED,JAMMED} private Status status = Status.DRY; private final int id; public Toast(int idn){id = idn;} public void butter(){ status = Status.BUTTERED; } public void jam(){ status = Status.JAMMED; } public Status getStatus(){ return status; } public int getId(){ return id; } public String toString(){ return "Toast " + id + " : " + status; } } class ToastQueue extends LinkedBlockingQueue<Toast>{} class Toaster implements Runnable{ private ToastQueue toastQueue; private int count = 0; private Random rand = new Random(47); public Toaster(ToastQueue tq){ toastQueue = tq; } public void run(){ try{ while (!Thread.interrupted()){ TimeUnit.MILLISECONDS.sleep(100 + rand.nextInt(100)); //Make toast Toast t = new Toast(count++); System.out.println(t); //Insert into queue toastQueue.put(t); } } catch (InterruptedException e) { System.out.println("Toaster interrupted"); } System.out.println("Toaster off"); } } //Apply butter to toast class Butterer implements Runnable{ private ToastQueue dryQueue ,butteredQueue; public Butterer(ToastQueue dry , ToastQueue buttered){ dryQueue = dry; butteredQueue = buttered; } public void run(){ try{ while (!Thread.interrupted()){ //Blocks until next piece of toast is available; Toast t = dryQueue.take(); t.butter(); System.out.println(t); butteredQueue.put(t); } } catch (InterruptedException e) { System.out.println("Butterer interrupted"); } System.out.println("Butterer off"); } } //Apply jam to buttered toast; class Jammer implements Runnable{ private ToastQueue butteredQueue,finishedQueue; public Jammer(ToastQueue buttered,ToastQueue finished){ butteredQueue = buttered; finishedQueue = finished; } public void run(){ try{ while (!Thread.interrupted()){ //Blocks until next piece of toast is available; Toast t = butteredQueue.take(); t.jam(); System.out.println(t); finishedQueue.put(t); } } catch (InterruptedException e) { System.out.println("Jammer interrupted"); } System.out.println("Jammer off"); } } //Consume the toast; class Eater implements Runnable{ private ToastQueue finishedQueue; private int counter = 0; public Eater(ToastQueue finished){ this.finishedQueue = finished; } public void run(){ try{ while (!Thread.interrupted()){ //Blocks until next piece of toast is available; Toast t = finishedQueue.take(); //Verify that the toast is coming in order; //and that all pieces are getting jammed; if(t.getId() != counter++ || t.getStatus() != Toast.Status.JAMMED){ System.out.println(">>>> Error : " + t); System.exit(1); }else{ System.out.println("Chomp ! " + t); } } } catch (InterruptedException e) { System.out.println("Eater interrupted"); } System.out.println("Eater off"); } } public class ToastOMatic { public static void main(String[] args) throws InterruptedException { ToastQueue dryQueue = new ToastQueue(), butteredQueue = new ToastQueue(), finishedQueue = new ToastQueue(); ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(new Toaster(dryQueue)); exec.execute(new Butterer(dryQueue,butteredQueue)); exec.execute(new Jammer(butteredQueue,finishedQueue)); TimeUnit.SECONDS.sleep(5); exec.shutdownNow(); } }
3. Console :
Toast 0 : DRY Toast 0 : BUTTERED Toast 0 : JAMMED Toast 1 : DRY Toast 1 : BUTTERED Toast 1 : JAMMED Toast 2 : DRY Toast 2 : BUTTERED Toast 2 : JAMMED Toast 3 : DRY Toast 3 : BUTTERED Toast 3 : JAMMED Toast 4 : DRY Toast 4 : BUTTERED Toast 4 : JAMMED Toast 5 : DRY Toast 5 : BUTTERED Toast 5 : JAMMED Toast 6 : DRY Toast 6 : BUTTERED Toast 6 : JAMMED Toast 7 : DRY Toast 7 : BUTTERED Toast 7 : JAMMED Toast 8 : DRY Toast 8 : BUTTERED Toast 8 : JAMMED Toast 9 : DRY Toast 9 : BUTTERED Toast 9 : JAMMED Toast 10 : DRY Toast 10 : BUTTERED Toast 10 : JAMMED Toast 11 : DRY Toast 11 : BUTTERED Toast 11 : JAMMED Toast 12 : DRY Toast 12 : BUTTERED Toast 12 : JAMMED Toast 13 : DRY Toast 13 : BUTTERED Toast 13 : JAMMED Toast 14 : DRY Toast 14 : BUTTERED Toast 14 : JAMMED Toast 15 : DRY Toast 15 : BUTTERED Toast 15 : JAMMED Toast 16 : DRY Toast 16 : BUTTERED Toast 16 : JAMMED Toast 17 : DRY Toast 17 : BUTTERED Toast 17 : JAMMED Toast 18 : DRY Toast 18 : BUTTERED Toast 18 : JAMMED Toast 19 : DRY Toast 19 : BUTTERED Toast 19 : JAMMED Toast 20 : DRY Toast 20 : BUTTERED Toast 20 : JAMMED Toast 21 : DRY Toast 21 : BUTTERED Toast 21 : JAMMED Toast 22 : DRY Toast 22 : BUTTERED Toast 22 : JAMMED Toast 23 : DRY Toast 23 : BUTTERED Toast 23 : JAMMED Toast 24 : DRY Toast 24 : BUTTERED Toast 24 : JAMMED Toast 25 : DRY Toast 25 : BUTTERED Toast 25 : JAMMED Toast 26 : DRY Toast 26 : BUTTERED Toast 26 : JAMMED Toast 27 : DRY Toast 27 : BUTTERED Toast 27 : JAMMED Toast 28 : DRY Toast 28 : BUTTERED Toast 28 : JAMMED Toast 29 : DRY Toast 29 : BUTTERED Toast 29 : JAMMED Toast 30 : DRY Toast 30 : BUTTERED Toast 30 : JAMMED Toast 31 : DRY Toast 31 : BUTTERED Toast 31 : JAMMED Toast 32 : DRY Toast 32 : BUTTERED Toast 32 : JAMMED Toast 33 : DRY Toast 33 : BUTTERED Toast 33 : JAMMED Jammer interrupted Jammer off Butterer interrupted Butterer off Toaster interrupted Toaster off
4. Toast是一个使用enum值的优秀示例。注意,这个示例中没有任何显式的同步(即使用Lock对象或synchronized关键字的同步),因为同步由队列(其内部是同步的)和系统的设计隐式地管理了 ------ 每片Toast在任何时刻都只由一个任务在操作。因为队列的阻塞,使得处理过程将被自动地挂起和恢复。你可以看到由BlockingQueue产生的简化十分明显。在使用显示的wait()和notifyAll()时存在的类和类之间的耦合被消除了,因为每个类都只和它的BlockingQueue通信。
5. 鸣谢
6. 啦啦啦