Chapter 21 - Exercise 29

(8) Modify ToastOMatic.java to create peanut butter and jelly on toast sandwiches using two separate assembly lines (one for peanut butter, the second for jelly, then merging the two lines).


总体思路很简单:

  1. 涂黄油的流水线就涂黄油。涂果酱的线就涂果酱。
  2. 关键步骤在于:黄油流水线下来再送到果酱流水线。果酱流水线下来再送到黄油流水线。
  3. 最后一道管卡把FINISH状态下的都过滤出来。

Toast29.java

吐司有四种状态,什么都没涂,只涂了黄油,只涂了果酱,黄油果酱都涂过了。注意黄油果酱的顺序不重要,只要都涂过就可以吃。另外涂过的不可以重复涂。所以peanutButter()和jamme()两个方法都用switch根据不同状态处理。相当于有限状态机。



package com.ciaoshen.thinkinjava.chapter21;
import java.util.concurrent.*;

public class Toast29{
    public static enum Status29{DRY, PBD, JMD, FINISH}
    private static int count=0;
    private int id;
    private Status29 status=Status29.DRY;
    public Toast29(){id=++count;}
    public synchronized void peanutButter(){
        switch(status){
            case DRY:
                status=Status29.PBD; break;
            case PBD:
                System.out.println("ERROR: "+this+" alread PeanutButtered!!!");break;
            case JMD:
                status=Status29.FINISH;break;
            case FINISH:
                System.out.println("ERROR: "+this+" alread finished!!!");break;
        }
    }
    public synchronized void jamme(){
        switch(status){
            case DRY:
                status=Status29.JMD; break;
            case JMD:
                System.out.println("ERROR: "+this+" alread Jammed!!!");break;
            case PBD:
                status=Status29.FINISH;break;
            case FINISH:
                System.out.println("ERROR: "+this+" alread finished!!!");break;
        }
    }
    public Status29 getStatus(){return status;}
    public void setStatus(Status29 s){status=s;}
    public String toString(){return "Toast#"+id+": "+status;}
}


ToastQueue29.java

BlockingQueue换个名字。



package com.ciaoshen.thinkinjava.chapter21;
import java.util.concurrent.*;

public class ToastQueue29 extends LinkedBlockingQueue<Toast29>{}


Toaster29.java

有两个这样专门生产原味吐司的线程,分别插进涂黄油队列和涂果酱队列。



package com.ciaoshen.thinkinjava.chapter21;
import java.util.concurrent.*;
import java.util.*;

public class Toaster29 implements Runnable{
    private ToastQueue29 toastQueue;
    private Random rand=new Random();

    public Toaster29(ToastQueue29 tq){toastQueue=tq;}
    public void run(){
        try{
            while(!Thread.interrupted()){
                TimeUnit.MILLISECONDS.sleep(100+rand.nextInt(100));
                Toast29 t=new Toast29();
                System.out.println(t);
                toastQueue.put(t);
            }
        }catch(InterruptedException ie){
            System.out.println("Toaster29 interrupted!");
        }finally{
            System.out.println("Toaster29 exit!");
        }
    }
}


PeanutButterer19.java

负责涂黄油的线程。



package com.ciaoshen.thinkinjava.chapter21;
import java.util.concurrent.*;
import java.util.*;

public class PeanutButterer29 implements Runnable{
    private ToastQueue29 toastQueue;
    private ToastQueue29 peanutButterQueue;
    public PeanutButterer29(ToastQueue29 tq, ToastQueue29 pbq){
        toastQueue=tq;
        peanutButterQueue=pbq;
    }
    public void run(){
        try{
            while(!Thread.interrupted()){
                Toast29 t=toastQueue.take();
                t.peanutButter();
                System.out.println(t);
                peanutButterQueue.put(t);
            }
        }catch(InterruptedException ie){
            System.out.println("Toaster29 interrupted!");
        }finally{
            System.out.println("Toaster29 exit!");
        }
    }
}


Jammer29.java

负责涂果酱的线程。



package com.ciaoshen.thinkinjava.chapter21;
import java.util.concurrent.*;
import java.util.*;

public class Jammer29 implements Runnable{
    private ToastQueue29 toastQueue;
    private ToastQueue29 jammeQueue;
    public Jammer29(ToastQueue29 tq, ToastQueue29 jmq){
        toastQueue=tq;
        jammeQueue=jmq;
    }
    public void run(){
        try{
            while(!Thread.interrupted()){
                Toast29 t=toastQueue.take();
                t.jamme();
                System.out.println(t);
                jammeQueue.put(t);
            }
        }catch(InterruptedException ie){
            System.out.println("Toaster29 interrupted!");
        }finally{
            System.out.println("Toaster29 exit!");
        }
    }
}


PBChecker29.java

从涂完黄油的队列里挑拣已经FINISH的和只涂了黄油的。只涂了黄油的再插入涂果酱流水线。FINISH的就等待被吃。



package com.ciaoshen.thinkinjava.chapter21;
import java.util.concurrent.*;
import java.util.*;

public class PBChecker29 implements Runnable{
    private ToastQueue29 peanutButteredQueue;
    private ToastQueue29 jammeQueue;
    private ToastQueue29 finishQueue;
    public PBChecker29(ToastQueue29 pbdq, ToastQueue29 jmq, ToastQueue29 fq){
        peanutButteredQueue=pbdq;
        jammeQueue=jmq;
        finishQueue=fq;
    }
    public void run(){
        try{
            while(!Thread.interrupted()){
                Toast29 t=peanutButteredQueue.take();
                switch(t.getStatus()){
                    case DRY:
                        System.out.println("ERROR: "+t+" still DRY, cannot PeanutButter!!!");break;
                    case PBD:
                        jammeQueue.put(t);break;
                    case JMD:
                        System.out.println("ERROR: "+t+" need to be PeanutButtered!!!");break;
                    case FINISH:
                        finishQueue.put(t);break;
                }
            }
        }catch(InterruptedException ie){
            System.out.println("Toaster29 interrupted!");
        }finally{
            System.out.println("Toaster29 exit!");
        }
    }
}


JMChecker29.java

同理,从涂完果酱的队列里挑拣已经FINISH的和只涂了果酱的。只涂了果酱的再插入涂黄油流水线。



package com.ciaoshen.thinkinjava.chapter21;
import java.util.concurrent.*;
import java.util.*;

public class JMChecker29 implements Runnable{
    private ToastQueue29 jammedQueue;
    private ToastQueue29 peanutButterQueue;
    private ToastQueue29 finishQueue;
    public JMChecker29(ToastQueue29 jmdq, ToastQueue29 pbq, ToastQueue29 fq){
        jammedQueue=jmdq;
        peanutButterQueue=pbq;
        finishQueue=fq;
    }
    public void run(){
        try{
            while(!Thread.interrupted()){
                Toast29 t=jammedQueue.take();
                switch(t.getStatus()){
                    case DRY:
                        System.out.println("ERROR: "+t+" still DRY, cannot Jamme!!!");break;
                    case PBD:
                        System.out.println("ERROR: "+t+" need to be Jammed!!!");break;
                    case JMD:
                        peanutButterQueue.put(t);break;
                    case FINISH:
                        finishQueue.put(t);break;
                }
            }
        }catch(InterruptedException ie){
            System.out.println("Toaster29 interrupted!");
        }finally{
            System.out.println("Toaster29 exit!");
        }
    }
}


Eater29.java

专门负责从成品吐司队列里拿来吃的线程。



package com.ciaoshen.thinkinjava.chapter21;
import java.util.concurrent.*;
import java.util.*;

public class Eater29 implements Runnable{
    private ToastQueue29 finishQueue;
    public Eater29(ToastQueue29 fq){
        finishQueue=fq;
    }
    public void run(){
        try{
            while(!Thread.interrupted()){
                Toast29 t=finishQueue.take();
                if(t.getStatus()!=Toast29.Status29.FINISH){
                    System.out.println("ERROR: "+t+" not Finished!");
                }else{
                    System.out.println(t+"  YAMMY! YAMMY!");
                }
            }
        }catch(InterruptedException ie){
            System.out.println("Toaster29 interrupted!");
        }finally{
            System.out.println("Toaster29 exit!");
        }
    }
}


Exercise29.java

创建这5个队列,7个线程。一起运行。他们之间就靠BlockingQueue的协调一起工作。



package com.ciaoshen.thinkinjava.chapter21;
import java.util.concurrent.*;

public class Exercise29{
    public static void main(String[] args){
        ToastQueue29 queuePB=new ToastQueue29();
        ToastQueue29 queueJM=new ToastQueue29();
        ToastQueue29 queuePBD=new ToastQueue29();
        ToastQueue29 queueJMD=new ToastQueue29();
        ToastQueue29 queueFINISH=new ToastQueue29();

        ExecutorService es=Executors.newCachedThreadPool();
        es.execute(new Toaster29(queuePB));
        es.execute(new Toaster29(queueJM));
        es.execute(new PeanutButterer29(queuePB,queuePBD));
        es.execute(new Jammer29(queueJM,queueJMD));
        es.execute(new PBChecker29(queuePBD,queueJM,queueFINISH));
        es.execute(new JMChecker29(queueJMD,queuePB,queueFINISH));
        es.execute(new Eater29(queueFINISH));

        try{
            TimeUnit.SECONDS.sleep(5);
        }catch(InterruptedException ie){
            System.out.println("Test Interrupted!");
        }finally{
            es.shutdownNow();
        }
    }
}



Need Java Developers? Hire Me »

I know Java. Talk is cheap, watch my code.

I live in CANADA now.