博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java并发(四)BlockingQueue的使用
阅读量:5996 次
发布时间:2019-06-20

本文共 6416 字,大约阅读时间需要 21 分钟。

  hot3.png

    wait()和notifyAll()方法以一种非常低级的方式解决了任务互操作的问题,即每次交互时都需要握手。在许多情况下,你可以瞄准更高的抽象级别,使用同步队列来解决任务协作的问题。同步队列在任何时刻都只允许一个任务插入或移除元素。在java.util.concurrent.BlockingQueue接口中提供了这个队列,这个接口有大量的标准实现。你通常可以使用LinkedBlockingQueue,它是一个无界队列,你还可以使用ArrayBlockingQueue,它具有固定的尺寸,因此你可以在它被阻塞之前,向其中放置有限数量的元素。

    如果消费者任务试图从队列中获取对象,而该队列此时为空,那么这些队列还可以挂起消费者任务,并且当有更多的元素可用时回复消费者任务。阻塞队列可以解决非常大的问题,而其方式与wait()和notifyAll()相比,则要简单并可靠许多。

    考虑下面这个BlockingQueue的示例,有一台机器具有三个任务:一个制作吐司,一个给吐司抹黄油,还有一个给吐司涂果酱。我们可以通过各个处理过程之间的BlockingQueue来运行这个吐司制作程序:

import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.LinkedBlockingQueue;import java.util.concurrent.TimeUnit;class Toast {    /**     * 吐司的状态:     * DRY: 烘干的     * BUTTERED: 涂了黄油的     * JAMMED: 涂了果酱的     * 

吐司的状态只能由DRY->BUTTERED->JAMMED转变     */    public enum Status {DRY, BUTTERED, JAMMED}    private Status status = Status.DRY;//默认状态为DRY    private final int id;    public Toast(int id) { this.id =  id;}    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: " + id + ", status: " + status;    }}@SuppressWarnings("serial")class ToastQueue extends LinkedBlockingQueue

 {}/** * 生产吐司的任务。 */class Toaster implements Runnable {    private ToastQueue toastQueue;    private int count = 0;    private Random random = new Random(47);    public Toaster(ToastQueue queue) {        this.toastQueue = queue;    }    @Override    public void run() {        try {            while(!Thread.interrupted()) {                TimeUnit.MILLISECONDS.sleep(300 + random.nextInt(500));                //生产一片吐司,这些吐司是有序的                Toast toast = new Toast(count++);                System.out.println(toast);                //放到toastQueue中                toastQueue.put(toast);            }        } catch (InterruptedException e) {            System.out.println("Toaster interrupted.");        }        System.out.println("Toaster off.");    }}/** * 涂黄油的任务。 */class Butterer implements Runnable {    private ToastQueue dryQueue;    private ToastQueue butteredQueue;    public Butterer(ToastQueue dryQueue, ToastQueue butteredQueue) {        this.dryQueue = dryQueue;        this.butteredQueue = butteredQueue;    }        @Override    public void run() {        try {            while(!Thread.interrupted()) {                //在取得下一个吐司之前会一直阻塞                Toast toast = dryQueue.take();                toast.butter();                System.out.println(toast);                butteredQueue.put(toast);            }        } catch (InterruptedException e) {            System.out.println("Butterer interrupted.");        }        System.out.println("Butterer off.");            }}/** * 涂果酱的任务。 */class Jammer implements Runnable {    private ToastQueue butteredQueue;    private ToastQueue finishedQueue;    public Jammer(ToastQueue butteredQueue, ToastQueue finishedQueue) {        this.finishedQueue = finishedQueue;        this.butteredQueue = butteredQueue;    }        @Override    public void run() {        try {            while(!Thread.interrupted()) {                //在取得下一个吐司之前会一直阻塞                Toast toast = butteredQueue.take();                toast.jam();                System.out.println(toast);                finishedQueue.put(toast);            }        } catch (InterruptedException e) {            System.out.println("Jammer interrupted.");        }        System.out.println("Jammer off.");    }}/** * 吃吐司的人,消费者。 */class Eater implements Runnable {    private ToastQueue finishedQueue;    private int count = 0;    public Eater (ToastQueue finishedQueue) {        this.finishedQueue = finishedQueue;    }    @Override    public void run() {        try {            while(!Thread.interrupted()) {                //在取得下一个吐司之前会一直阻塞                Toast toast = finishedQueue.take();                //验证取得的吐司是有序的,而且状态是JAMMED的                if (toast.getId() != count++ ||                         toast.getStatus() != Toast.Status.JAMMED) {                    System.out.println("Error -> " + toast);                    System.exit(-1);                } else {                    //吃掉吐司                    System.out.println(toast + "->Eaten");                }            }        } catch (InterruptedException e) {            System.out.println("Eater interrupted.");        }        System.out.println("Eater off.");    }}public class ToastOMatic {    public static void main(String[] args) throws Exception {        ToastQueue dryQueue = new ToastQueue();        ToastQueue butteredQueue = new ToastQueue();        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));        exec.execute(new Eater(finishedQueue));        TimeUnit.SECONDS.sleep(5);        exec.shutdownNow();    }}

 

执行结果(可能的结果):

Toast id: 0, status: DRYToast id: 0, status: BUTTEREDToast id: 0, status: JAMMEDToast id: 0, status: JAMMED->EatenToast id: 1, status: DRYToast id: 1, status: BUTTEREDToast id: 1, status: JAMMEDToast id: 1, status: JAMMED->EatenToast id: 2, status: DRYToast id: 2, status: BUTTEREDToast id: 2, status: JAMMEDToast id: 2, status: JAMMED->EatenToast id: 3, status: DRYToast id: 3, status: BUTTEREDToast id: 3, status: JAMMEDToast id: 3, status: JAMMED->EatenToast id: 4, status: DRYToast id: 4, status: BUTTEREDToast id: 4, status: JAMMEDToast id: 4, status: JAMMED->EatenToast id: 5, status: DRYToast id: 5, status: BUTTEREDToast id: 5, status: JAMMEDToast id: 5, status: JAMMED->EatenToast id: 6, status: DRYToast id: 6, status: BUTTEREDToast id: 6, status: JAMMEDToast id: 6, status: JAMMED->EatenToast id: 7, status: DRYToast id: 7, status: BUTTEREDToast id: 7, status: JAMMEDToast id: 7, status: JAMMED->EatenEater interrupted.Eater off.Butterer interrupted.Toaster interrupted.Toaster off.Jammer interrupted.Jammer off.Butterer off.

 

    Toast是一个使用enum值的优秀示例。注意,这个示例中没有任何显式的同步(即使用Lock对象或者synchronized关键字的同步),因为同步已经由队列和系统的设计隐式的管理了——每片Toast在任何时刻都只由一个任务在操作。因为队列的阻塞,使得处理过程将被自动的挂起和恢复。你可以看到由BlockingQueue产生的简化十分明显。在使用显式的wait()和notifyAll()时存在的类和类之间的耦合被消除了,因为每个类都只和它的BlockingQueue通信。

转载于:https://my.oschina.net/itblog/blog/515735

你可能感兴趣的文章
程序员面试笔试宝典学习记录(三)(数据库相关知识)
查看>>
memcahced 更新
查看>>
mysql自增列导致主键重复问题分析。。。
查看>>
KVC & KVO
查看>>
<第一次买基金就赚钱>读书笔记
查看>>
说说设计模式~门面模式(Facade)
查看>>
多种方法求解八数码问题
查看>>
程序员如何多线程工作,做个职场达人
查看>>
开机黑屏 仅仅显示鼠标 电脑黑屏 仅仅有鼠标 移动 [已成功解决]
查看>>
服务器资源管理器视图的添加显示的步骤
查看>>
ThreadPoolExecutor使用介绍
查看>>
[原]pomelo开发环境搭建
查看>>
Java Swing 探索(一)LayoutManager
查看>>
VS2010 使用TeeChart画图控件 - 之二 - 绘制图形(折线图,柱状图)
查看>>
SenTestingKit.framework的报错!
查看>>
ArcSDE SDK For Java二次开发介绍、演示样例
查看>>
Oracle 优化器
查看>>
oracle HA 高可用性具体解释(之中的一个)
查看>>
【转载】用Pwnage + Redsnow 制作完美越狱固件
查看>>
bit byte哪些事
查看>>