java编程思想笔记-并发之线程协作(四)

1.生产者,消费者队列

wait()和notifyAll()方法以每次交互握手的方式解决任务操作问题,concurrent类库使用BlockingQueue同步队列来解决任务的协作问题,同步队列在任何时刻只允许一个任务插入或者移除元素,这个接口有两个常用的实现LinkedBlockingQueue和ArrayBlockingQueue,前者是无界队列,后者具有固定的尺寸
如果消费者尝试获取空队列元素,那么这个队列可以挂起消费者,并在更多的元素可用时恢复消费者队列

示例
制作一个吐司需要烘干吐司,抹黄油,涂果酱三个步骤,利用BlockingQueue模拟吐司工厂生产吐司

class Toast{
    public enum Status{
        DRY,BUFFERED,JAMMED
    }
    private Status status=Status.DRY;
    private final int id;
    public Toast(int idn){
        this.id=idn;
    }
    public void butter(){
        status=Status.BUFFERED;
    }
    public void jam(){
        status=Status.JAMMED;
    }
    public Status getStatus(){
        return status;
    }
    public int getId(){
        return id;
    }
    @Override
    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){
        this.toastQueue=tq;
    }
    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                TimeUnit.MILLISECONDS.sleep(100+rand.nextInt(500));
                Toast t=new Toast(count++);
                System.out.println(t);
                toastQueue.put(t);
            }
        } catch (Exception e) {
            System.out.println("ToasterInterruptException ");
        }
        System.out.println("Toaster off");
    }
}

class Butter implements Runnable{
    private ToastQueue dryQueue,butteredQueue;
    public Butter(ToastQueue dry,ToastQueue buttered) {
        dryQueue=dry;
        butteredQueue=buttered;
    }
    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                Toast t=dryQueue.take();
                t.butter();
                System.out.println(t);
                butteredQueue.put(t);
            }
        } catch (Exception e) {
            System.out.println("Butterer interrupted ");
        }
        System.out.println("Butterer off");
    }
}

class Jammer implements Runnable{
    private ToastQueue butteredQueue,finishedQueue;
    public Jammer(ToastQueue butteredQueue,ToastQueue finishedQueue){
        this.butteredQueue=butteredQueue;
        this.finishedQueue=finishedQueue;
    }
    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                Toast t=butteredQueue.take();
                t.jam();
                System.out.println(t);
                finishedQueue.put(t);
            }
        } catch (Exception e) {
            System.out.println("Jammer Interrupted");
        }
        System.out.println("Jammer Off");
    }
}

class Eater implements Runnable{
    private ToastQueue finishedQueue;
    private int counter;
    public Eater(ToastQueue finished){
        this.finishedQueue=finished;
    }
    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                Toast t=finishedQueue.take();
                if (t.getId()!=counter++||t.getStatus()!=Toast.Status.JAMMED) {
                    System.err.println(">>>> Error:"+t);
                    System.exit(1);
                }else {
                    System.out.println("Chomp!"+t);
                }
            }
        } catch (Exception e) {
            System.out.println("Easter interrupted");
        }
        System.out.println("Easter 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 Butter(dryQueue, butteredQueue));
        exec.execute(new Jammer(butteredQueue, finishedQueue));
        exec.execute(new Eater(finishedQueue));
        TimeUnit.SECONDS.sleep(5);
        exec.shutdownNow();
    }
}

从示例2可以看到,利用BlockingQueue避免了显示的使用wait,notify等方法

2.任务间使用管道输入输出

有时候需要利用输入输出在线程间通信,它们在Java输入输出类库中的对应物是PipedReader和PipedWriter,PipedReader是可中断的,interrupt()可以打断阻塞,而System.in.read()是不可中断的

示例:
利用PipedReader和PipedWriter打印26个大小写字母

class Sender implements Runnable{
    private Random random=new Random(47);
    private PipedWriter out=new PipedWriter();
    public PipedWriter getPipedWriter(){
        return out;
    }
    @Override
    public void run() {
        try {
            while (true) {
                for (char c='A';c<='z';c++) {
                    out.write(c);
                    TimeUnit.MILLISECONDS.sleep(random.nextInt(500));
                }
            }
        } catch (IOException e) {
            System.out.println("Sender-IOException");
        } catch (InterruptedException e) {
            System.out.println("Sender-InterruptedException");
        }
    }
}

class Receiver implements Runnable{
    private PipedReader in;
    public Receiver(Sender sender) throws IOException{
        in=new PipedReader(sender.getPipedWriter());
    }
    @Override
    public void run() {
        try {
            while (true) {
                System.out.println("Read:"+(char)in.read()+",");
            }
        } catch (Exception e) {
            System.out.println("Receiver-IOException");
        }
    }
}

public class PipedIO {
    public static void main(String[] args) throws Exception {
        Sender sender=new Sender();
        Receiver receiver=new Receiver(sender);
        ExecutorService exec=Executors.newCachedThreadPool();
        exec.execute(sender);
        exec.execute(receiver);
        TimeUnit.SECONDS.sleep(20);
        exec.shutdownNow();
    }
}

示例
利用BlockingQueue重写大小写字母示例

class Sender2 implements Runnable{
    private Random random=new Random(47);
    BlockingQueuebq;
    public Sender2(BlockingQueuebq){
        this.bq=bq;
    }
    @Override
    public void run() {
        try {
            while (true) {
                for (char c='A';c<='z';c++) {
                    bq.add(c);
                    TimeUnit.MILLISECONDS.sleep(random.nextInt(500));
                }
            }
        } catch (InterruptedException e) {
            System.out.println("Sender2-InterruptedException");
        }
    }
}

class Receiver2 implements Runnable{
    BlockingQueuebq;
    public Receiver2(BlockingQueuebq){
        this.bq=bq;
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                char c=bq.take();
                System.out.println("receive:"+c);
            }
        } catch (InterruptedException e) {
            System.out.println("Receiver2-InterruptedException");
        }
    }

}

public class PipedIOBlockingQueue {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService exec=Executors.newCachedThreadPool();
        BlockingQueuequeue=new LinkedBlockingQueue();
        exec.execute(new Sender2(queue));
        exec.execute(new Receiver2(queue));
        TimeUnit.SECONDS.sleep(5);
        exec.shutdownNow();
    }
}

你可能感兴趣的:(并发,java)