这一节我们来了解阻塞队列(BlockingQueue),BlockingQueue接口定义了一种阻塞的FIFO queue,每一个BlockingQueue都有一个容量,当容量满时往BlockingQueue中添加数据时会造成阻塞,当容量为空时取元素操作会阻塞。首先我们来看ArrayBlockingQueue和LinkedBlockingQueue.

ArrayBlockingQueue

ArrayBlockingQueue是一个用数组实现的有界阻塞队列。此队列按照先进先出(FIFO)的原则对元素进行排序。默认情况下不保证访问者公平的访问队列,所谓公平访问队列是指阻塞的所有生产者线程或消费者线程,当队列可用时,可以按照阻塞的先后顺序访问队列,即先阻塞的生产者线程,可以先往队列里插入元素,先阻塞的消费者线程,可以先从队列里获取元素。通常情况下为了保证公平性会降低吞吐量。

我们看他的构造函数实现:

//默认是非公平的,初始指定队列容量
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
} //该构造方法可以设置队列的公平性。当然如果为公平的,则对性能会产生影响
//访问者的公平性是使用可重入锁实现的
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}

使用很简单我们直接看一个实例:

public class ProducerConsumerTest {
public static void main(String[] args) { final BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(3); ExecutorService service = Executors.newFixedThreadPool(10); for(int i = 0;i<4;i++){
service.execute(new ProducerAndConsumer(blockingQueue));
}
}
} class ProducerAndConsumer implements Runnable{
private boolean flag = false; private Integer j = 1; private Lock lock = new ReentrantLock(); Condition pro_con = lock.newCondition(); Condition con_con = lock.newCondition(); private BlockingQueue<Integer> blockingQueue; public ProducerAndConsumer(BlockingQueue<Integer> blockingQueue){
this.blockingQueue= blockingQueue;
} //生产
public void put(){
try {
lock.lock();
while(flag)
pro_con.await();
System.out.println("正在准备放入数据。。。");
Thread.sleep(new Random().nextInt(10)*100);
Integer value = new Random().nextInt(30);
blockingQueue.put(value);
System.out.println(Thread.currentThread().getName()+" 放入的数据 "+value);
flag = true;
con_con.signal();
} catch (Exception e) {
e.printStackTrace();
}
finally{
lock.unlock();
}
} public void get(){
try {
lock.lock();
while(!flag)
con_con.await();
System.out.println("正在准备取数据。。。");
Thread.sleep(new Random().nextInt(10)*1000);
System.out.println(Thread.currentThread().getName()+" 取到的数据为"+blockingQueue.take());
flag = false;
pro_con.signal();
} catch (Exception e) {
e.printStackTrace();
}
finally{
lock.unlock();
}
} @Override
public void run() { while(true){
if(j==1){
put();
}
else{
get();
}
j=(j+1)%2;
}
}
}

输出为:

正在准备放入数据。。。
正在准备放入数据。。。
正在准备放入数据。。。
正在准备放入数据。。。
pool-1-thread-2 放入的数据 13
正在准备取数据。。。
pool-1-thread-3 放入的数据 4
正在准备取数据。。。
pool-1-thread-3 取到的数据为13
正在准备放入数据。。。
pool-1-thread-1 放入的数据 11
正在准备取数据。。。
pool-1-thread-4 放入的数据 26
正在准备取数据。。。
pool-1-thread-1 取到的数据为4
正在准备放入数据。。。
pool-1-thread-2 取到的数据为11
正在准备放入数据。。。
pool-1-thread-3 放入的数据 18
正在准备取数据。。。
...
...

LinkedBlockingQueue

LinkedBlockingQueue是一个用链表实现的有界阻塞队列。此队列的默认和最大长度为Integer.MAX_VALUE。此队列按照先进先出的原则对元素进行排序。

先看一下他的构造函数:

public LinkedBlockingQueue() {
this(Integer.MAX_VALUE); //MAX_VALUE=2147483647
} public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}

我们还是直接开看一个例子:

public class BlockingQueueTest {

    /**
* 定义装苹果的篮子
*/
public static class Basket {
// 篮子,能够容纳3个苹果
// BlockingQueue<String> basket = new ArrayBlockingQueue<String>(3);
BlockingQueue<String> basket = new LinkedBlockingQueue<String>(3); // 生产苹果,放入篮子
public void produce() throws InterruptedException {
// put方法放入一个苹果,若basket满了,等到basket有位置
basket.put("An apple");
} // 消费苹果,从篮子中取走
public String consume() throws InterruptedException {
// get方法取出一个苹果,若basket为空,等到basket有苹果为止
return basket.take();
}
} //  测试方法
public static void testBasket() { // 建立一个装苹果的篮子
final Basket basket = new Basket(); // 定义苹果生产者
class Producer implements Runnable {
public String instance = ""; public Producer(String a) {
instance = a;
} public void run() {
try {
while (true) {
// 生产苹果
System.out.println("生产者准备生产苹果:" + instance);
basket.produce();
System.out.println("! 生产者生产苹果完毕:" + instance);
// 休眠300ms
Thread.sleep(300);
}
} catch (InterruptedException ex) {
}
}
} // 定义苹果消费者
class Consumer implements Runnable {
public String instance = ""; public Consumer(String a) {
instance = a;
} public void run() {
try {
while (true) {
// 消费苹果
System.out.println("消费者准备消费苹果:" + instance);
basket.consume();
System.out.println("! 消费者消费苹果完毕:" + instance);
// 休眠1000ms
Thread.sleep(1000);
}
} catch (InterruptedException ex) {
}
}
} ExecutorService service = Executors.newCachedThreadPool();
Producer producer = new Producer("P1");
Producer producer2 = new Producer("P2");
Consumer consumer = new Consumer("C1");
service.submit(producer);
service.submit(producer2);
service.submit(consumer); // 程序运行3s后,所有任务停止
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
} service.shutdownNow();
} public static void main(String[] args) {
BlockingQueueTest.testBasket();
}
}

输出为:

生产者准备生产苹果:P1
消费者准备消费苹果:C1
! 生产者生产苹果完毕:P1
生产者准备生产苹果:P2
! 消费者消费苹果完毕:C1
! 生产者生产苹果完毕:P2
生产者准备生产苹果:P2
! 生产者生产苹果完毕:P2
生产者准备生产苹果:P1
! 生产者生产苹果完毕:P1
生产者准备生产苹果:P2
生产者准备生产苹果:P1
消费者准备消费苹果:C1
! 消费者消费苹果完毕:C1
! 生产者生产苹果完毕:P2
生产者准备生产苹果:P2
消费者准备消费苹果:C1
! 消费者消费苹果完毕:C1
! 生产者生产苹果完毕:P1
生产者准备生产苹果:P1
消费者准备消费苹果:C1
! 消费者消费苹果完毕:C1
! 生产者生产苹果完毕:P2 Process finished with exit code 0

java并发编程(二十四)----(JUC集合)ArrayBlockingQueue和LinkedBlockingQueue介绍的更多相关文章

  1. java并发编程(十四)----(JUC原子类)对象的属性修改类型介绍

    今天我们介绍原子类的最后一个类型--对象的属性修改类型: AtomicIntegerFieldUpdater,AtomicLongFieldUpdater,AtomicReferenceFieldUp ...

  2. Java并发编程(十四)Java内存模型

    1.共享内存和消息传递 线程之间的通信机制有两种:共享内存和消息传递:在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信.在消息传递的并发模型里,线程 ...

  3. Java并发编程(十四)-- 线程池实现原理

    在上一章我们从宏观上介绍了ThreadPoolExecutor,本文将深入解析一下线程池的具体实现原理 原理解析 线程池状态 在ThreadPoolExecutor中定义了一个volatile变量,另 ...

  4. Java并发编程(十四)并发容器类

    同步容器将所有对容器状态的访问都串行化,以实现线程安全性.这种方法的代价是严重降低并发性,当多个线程竞争容器的锁时,吞吐量将严重减低. 另一个方面,并发容器是针对多个线程并发访问设计的.在java 5 ...

  5. java并发编程(十)----JUC原子类介绍

    今天我们来看一下JUC包中的原子类,所谓原子操作是指不会被线程调度机制打断的操作:这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程),原子操作可以是 ...

  6. java并发编程(十四)同步问题的内存可见性

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17288243 加锁(synchronized同步)的功能不仅仅局限于互斥行为,同时还存在另 ...

  7. java并发编程(十一)----(JUC原子类)基本类型介绍

    上一节我们说到了基本原子类的简单介绍,这一节我们先来看一下基本类型: AtomicInteger, AtomicLong, AtomicBoolean.AtomicInteger和AtomicLong ...

  8. Java并发编程二三事

    Java并发编程二三事 转自我的Github 近日重新翻了一下<Java Concurrency in Practice>故以此文记之. 我觉得Java的并发可以从下面三个点去理解: * ...

  9. java并发编程笔记(四)——安全发布对象

    java并发编程笔记(四)--安全发布对象 发布对象 使一个对象能够被当前范围之外的代码所使用 对象逸出 一种错误的发布.当一个对象还没构造完成时,就使它被其他线程所见 不安全的发布对象 某一个类的构 ...

随机推荐

  1. 个人博客小案例(纯Django搭建)

    在看这篇文章的时候,必须有django基础,如果没有点击访问 一.环境配置 新建项目并做配置项目创建,创建APP并注册 创建模板并配置相应的路径,点击下载模板,配置方法点击访问 创建静态文件并配置,点 ...

  2. HDU 5792:World is Exploding(树状数组求逆序对)

    http://acm.hdu.edu.cn/showproblem.php?pid=5792 World is Exploding Problem Description   Given a sequ ...

  3. mysql计算日期之间相差的天数

    TO_DAYS(NOW()) - TO_DAYS(createTime) as dayFactor,

  4. 获取当前时间的MySql时间函数

    mysql> select current_timestamp(); +---------------------+ | current_timestamp() | +------------- ...

  5. .Net进程外session配置

    配置步骤: 1.开启 ASP.NET状态服务:cmd状态下:services.msc 2.配置web.config文件,在system.web下加入如下配置 <sessionState mode ...

  6. STM32F0_HAL库驱动描述——HAL驱动程序概述

    HAL库文件结构: HAL驱动文件: 外设驱动API文件和头文件:包含了常见主要的通用API,其中ppp表示外设名称,如adc.usart.gpio.irda等: stm32f0xx_hal_ppp. ...

  7. 使用反射机制将对象序列化Json

    一 思路 获取对象的Class对象. 获取对象的属性数组, 迭代属性数据拼接属性名与属性值, 存入List. 将List转换为流库, 再将流库使用逗号分隔符转换为字符串, 去掉首尾的逗号 二 代码 p ...

  8. panic: time: missing Location in call to Time.In

    docker容器发布go项目出现以下问题: panic: time: missing Location in call to Time.In COPY --from=build /usr/share/ ...

  9. Java 8 终于支持 Docker!

    Java 8曾经与Docker无法很好地兼容性,现在问题已消失. 请注意:我在本文中使用采用GNU GPL v2许可证的OpenJDK官方docker映像.在Oracle Java SE中,这里描述的 ...

  10. (转)Vix_API 操作 VMware

    对虚拟机(VMware Workstation)进行程序控制,查询了VMware官方网站的一些内容,但调试的时候还是出现很多问题. 刚开始想通过命令行的方式控制虚拟机,但总是存在一些问题,到现在也没搞 ...