想必大家都很熟悉生产者-消费者队列,生产者负责添加元素到队列,如果队列已满则会进入阻塞状态直到有消费者拿走元素。相反,消费者负责从队列中拿走元素,如果队列为空则会进入阻塞状态直到有生产者添加元素到队列。BlockingQueue就是这么一个生产者-消费者队列。

BlockingQueue是Queue的子接口

public interface BlockingQueue<E> extends Queue<E>

BlockingQueue拿走元素时,如果队列为空,阻塞等待会有两种情况:

一种是一直等待直到队列不为空,这种情况调用take方法

E take() throws InterruptedException;

另一种就是设定一个超时时间,一直等到超时,这种情况调用的是pool方法

E poll(long timeout, TimeUnit unit) throws InterruptedException;

同样对于添加元素来说,也有两种情况:

一直等待使用put方法

void put(E e) throws InterruptedException;

超时等待使用offer方法

boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException;

BlockingQueue的父接口Queue关于拿走元素的接口有两个:remove和pool。

两者的区别在于当队列为空时前者会抛出NoSuchElementException,而后者返回null。

E remove();
E poll();

添加元素的接口也有两个:add和offer。两者的区别在于当队列为满时前者会抛出IllegalStateException,而后者返回false。

boolean add(E e);
boolean offer(E e);

一般来说Queue类型的数据结构会有两种实现:数组和链表。对应到BlockingQueue就是ArrayBlockingQueue和LinkedBlockingQueue,两者都是基于AbstractQueue实现的。

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable

这里很有必要说说AbstractQueue,AbstractQueue只是实现了add和remove方法,而且很有意思的是这两个方法都是借助他们对应的无异常版本的方法offer和pool来实现的。

    public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
    public E remove() {
E x = poll();
if (x != null)
return x;
else
throw new NoSuchElementException();
}

这样做的好处无疑是提供了良好的扩展性,也就是把真正添加/拿走元素的实现留给子类来完成(可以实现线程安全和非线程安全两个版本)。

研究BlockingQueue关注的重点就是Blocking是如果实现的,接下来的两篇文章将会详细分析ArrayBlockingQueue和LinkedBlockingQueue如何实现线程的Blocking。

《java.util.concurrent 包源码阅读》05 BlockingQueue的更多相关文章

  1. 《java.util.concurrent 包源码阅读》 结束语

    <java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...

  2. 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分

    这一部分来说说线程池如何进行状态控制,即线程池的开启和关闭. 先来说说线程池的开启,这部分来看ThreadPoolExecutor构造方法: public ThreadPoolExecutor(int ...

  3. 《java.util.concurrent 包源码阅读》02 关于java.util.concurrent.atomic包

    Aomic数据类型有四种类型:AomicBoolean, AomicInteger, AomicLong, 和AomicReferrence(针对Object的)以及它们的数组类型, 还有一个特殊的A ...

  4. 《java.util.concurrent 包源码阅读》04 ConcurrentMap

    Java集合框架中的Map类型的数据结构是非线程安全,在多线程环境中使用时需要手动进行线程同步.因此在java.util.concurrent包中提供了一个线程安全版本的Map类型数据结构:Concu ...

  5. 《java.util.concurrent 包源码阅读》17 信号量 Semaphore

    学过操作系统的朋友都知道信号量,在java.util.concurrent包中也有一个关于信号量的实现:Semaphore. 从代码实现的角度来说,信号量与锁很类似,可以看成是一个有限的共享锁,即只能 ...

  6. 《java.util.concurrent 包源码阅读》06 ArrayBlockingQueue

    对于BlockingQueue的具体实现,主要关注的有两点:线程安全的实现和阻塞操作的实现.所以分析ArrayBlockingQueue也是基于这两点. 对于线程安全来说,所有的添加元素的方法和拿走元 ...

  7. 《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇

    concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void ...

  8. 《java.util.concurrent 包源码阅读》10 线程池系列之AbstractExecutorService

    AbstractExecutorService对ExecutorService的执行任务类型的方法提供了一个默认实现.这些方法包括submit,invokeAny和InvokeAll. 注意的是来自E ...

  9. 《java.util.concurrent 包源码阅读》22 Fork/Join框架的初体验

    JDK7引入了Fork/Join框架,所谓Fork/Join框架,个人解释:Fork分解任务成独立的子任务,用多线程去执行这些子任务,Join合并子任务的结果.这样就能使用多线程的方式来执行一个任务. ...

随机推荐

  1. Hadoop(八)Java程序访问HDFS集群中数据块与查看文件系统

    前言 我们知道HDFS集群中,所有的文件都是存放在DN的数据块中的.那我们该怎么去查看数据块的相关属性的呢?这就是我今天分享的内容了 一.HDFS中数据块概述 1.1.HDFS集群中数据块存放位置 我 ...

  2. DOS常用命令及进制转换

    DOS是一种用户单任务磁盘操作系统.在DOS中,我们可以通过DOS命令来管理设备和文件,如打印文件.删除文件,复制文件,创建新的文件夹和文档并编写内容等功能同时也是JAVA编程基础的一个入门.进入DO ...

  3. 解决Ubuntu中phpmyadmin对数据上传上限2M

    本文部分参考自:http://www.myhack58.com/Article/sort099/sort0102/2011/29396.htm 原文有少量错误或者过时的(相对于ubuntu15来说)内 ...

  4. 基于HTML5的WebGL实现json和echarts图表展现在同一个界面

    突然有个想法,如果能把一些用到不同的知识点放到同一个界面上,并且放到一个盒子里,这样我如果要看什么东西就可以很直接显示出来,而且这个盒子一定要能打开.我用HT实现了我的想法,代码一百多行,这么少的代码 ...

  5. 同步IO和异步IO

    链接: 同步IO和异步IO socket阻塞与非阻塞,同步与异步.I/O模型 Linux的IO系统常用系统调用及分析 linux异步IO的两种方式

  6. Python装饰器,json,pickle

    装饰器 定义:本质是函数,装饰其它函数是为了给其添加新功能: 原则:1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 实现装饰器知识储备: 1.函数即变量: 2.高阶函数 3.嵌套 ...

  7. C 其他一些

    1.联合,语法 union{成员1;成员2;} 联合间的成员共享同一个空间,也就是说,成员1赋值如果没有被清除,会体现在成员2上 2.位字段,结合结构体瓜分完整的类型存储空间,如 struct{ ; ...

  8. Windows下Mysql5.7开启binlog步骤及注意事项

    1.查看是否开启了binlog:show binary logs; 默认情况下是不开启的. 2.开启binlog:修改mysql的配置文件my.ini.添加如下配置: 该文件默认不允许修改,需要右键“ ...

  9. C# AOP 面向切面编程之 调用拦截

    有时候我们需要在代码中对方法调用进行拦截,并修改参数和返回值,这种操作叫做AOP(面向切面编程) 不过需要注意的是,AOP的效率很慢,在需要高效率场合慎用. 以下是C#的AOP方法: 首先建立一个控制 ...

  10. C++const使用(06)

    可以在类中使用const关键字定义数据成员和成员函数或修饰一个对象.一个const对象只能访问const成员函数,否则将产生编译错误. 常量成员 常量成员包括常量数据成员.静态常数据成员和常引用.静态 ...