1.什么是阻塞队列?

所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了.

看一下线程的四种状态,首先是新创建一个线程,然后,通过start方法启动线程--->线程变为可运行可执行状态,然后通过数据产生共享,线程产生互斥---->线程状态变为阻塞状态---->阻塞状态想打开的话可以调用notify方法.

这里Java5中提供了封装好的类,可以直接调用然后构造阻塞状态,以保证数据的原子性.

2.如何实现?

主要是实现BlockingQueue接口.

比较常见的实现有:ArrayBlockingQueue,LinkedBlockingQueue,DelayedWorkQueue等竺

这里简单介绍ArrayBlockingQueue;

//方式1
new ArrayBlockingQueue(int capacity);//Parameters:capacity the capacity of this queue//方式2
public ArrayBlockingQueue(int capacity, boolean fair) ;//fair if true then queue accesses for threads blocked on insertion or removal, are processed in FIFO order; if false the access order is unspecified.//方式3public ArrayBlockingQueue(int capacity, boolean fair,Collection<? extends E> c) ;//c the collection of elements to initially contain

三种构造函数,比较常用的是1,2两种,2比1只是多了要不要排序,如果排序,那就是FIFO原则,即先进先出.

3.举例:

package com.amos.concurrent;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;/**
* @ClassName: BlockingQueueTest
* @Description: Java5新特性,阻塞队列
* @author: amosli
* @email:hi_amos@outlook.com
* @date Apr 27, 2014 10:01:51 PM
*/
public class BlockingQueueTest {public static void main(String[] args) {final BlockingQueue queue = new ArrayBlockingQueue(3);for(int i=0;i<2;i++){new Thread(){public void run(){while(true){try {Thread.sleep((long)(Math.random()*1000));System.out.println(Thread.currentThread().getName() + "准备放数据!");                             queue.put(1);System.out.println(Thread.currentThread().getName() + "已经放了数据," +                             "队列目前有" + queue.size() + "个数据");} catch (InterruptedException e) {e.printStackTrace();}}}}.start();}new Thread(){public void run(){while(true){try {//将此处的睡眠时间分别改为100和1000,观察运行结果Thread.sleep(100);System.out.println(Thread.currentThread().getName() + "准备取数据!");queue.take();System.out.println(Thread.currentThread().getName() + "已经取走数据," +                             "队列目前有" + queue.size() + "个数据");                    } catch (InterruptedException e) {e.printStackTrace();}}}}.start();            }
}

效果如下图所示:

说明:这里新建一个队列后,主要调用的是put和take两种方法,一个是存,一个是取,这里由于将取的间隔时间设置的比较短,所以基本队列就没放满过.

4.改写之前的代码

方法1:Java核心知识点学习----多线程并发之线程间的通信,notify,wait

方法2:Java核心知识点学习----使用Condition控制线程通信

方法3:使用ArrayBlockingQueue

package com.amos.concurrent;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/**
* @ClassName: BlockingQueueCondition
* @Description: 在前面用Condition实现的同步通知的例子的基础上,改为用阻塞队列来实现。
第一个线程:A.take()……..B.put()
第二个线程:B.take()……..A.put()
* @author: amosli
* @email:hi_amos@outlook.com
* @date Apr 28, 2014 12:57:51 AM
*/
public class BlockingQueueCondition {public static void main(String[] args) {ExecutorService service = Executors.newSingleThreadExecutor();final Business3 business = new Business3();service.execute(new Runnable(){public void run() {for(int i=0;i<2;i++){business.sub();}}});for(int i=0;i<3;i++){business.main();}}}class Business3{BlockingQueue subQueue = new ArrayBlockingQueue(1);BlockingQueue mainQueue = new ArrayBlockingQueue(1);{try {mainQueue.put(1);} catch (InterruptedException e) {e.printStackTrace();}}public void sub(){try{mainQueue.take();for(int i=0;i<10;i++){System.out.println(Thread.currentThread().getName() + " : " + i);}subQueue.put(1);}catch(Exception e){}}public void main(){try{subQueue.take();for(int i=0;i<5;i++){System.out.println(Thread.currentThread().getName() + " : " + i);}mainQueue.put(1);}catch(Exception e){}        }
}

功能的实现都是完全一样的,不同的是,使用ArrayBlockingQueue会更简单.

5.官方---代码示例

典型的生产者消费者模型:

package com.amos.concurrent;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;/**
* @ClassName: BlockingSample
* @Description: 生产者消费者模型,阻塞,只有生产好了,才能去消费
* @author: amosli
* @email:hi_amos@outlook.com
* @date Apr 28, 2014 1:44:07 AM
*/
public class BlockingSample {public static void main(String[] args) {new BlockingSample().new Setup().main();}class Producer implements Runnable {private final BlockingQueue queue;Producer(BlockingQueue q) { queue = q; }public void run() {try {while (true) { queue.put(produce());System.out.println(Thread.currentThread().getName()+" 现在正在生产!");}} catch (Exception ex) { ex.printStackTrace();}}String produce() { System.out.println("produce now ....");return "produce"; }}class Consumer implements Runnable {private final BlockingQueue queue;Consumer(BlockingQueue q) { queue = q; }public void run() {try {while (true) { consume(queue.take()); System.out.println(Thread.currentThread().getName()+" 现在正在消费!");}} catch (InterruptedException ex) { ex.printStackTrace();}}void consume(Object x) {System.out.println("consume...");}}class Setup {void main() {BlockingQueue q = new ArrayBlockingQueue<String>(1);Producer p = new Producer(q);Consumer c1 = new Consumer(q);Consumer c2 = new Consumer(q);new Thread(p).start();new Thread(c1).start();new Thread(c2).start();}}}

效果如下图所示:

由图上可以看出,只有生产了才能消费,否则会形成阻塞.

Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍相关推荐

  1. java核心知识点学习----多线程间的数据共享的几种实现方式比较

    需求:设计4个线程,其中两个线程每次对j增加1,另外两个线程对j减少1. 实现数据共享的几种方式比较: 1.使用同一个runnable对象 如果每个线程执行的代码相同,那么可以使用同一个runnabl ...

  2. Java多线程-新特征-阻塞队列ArrayBlockingQueue

    阻塞队列是Java5线程新特征中的内容,Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue,阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素 ...

  3. 阻塞队列 java 源码_Java源码解析阻塞队列ArrayBlockingQueue常用方法

    本文基于jdk1.8进行分析 首先看一下ArrayBlockingQueue的成员变量.如下图.最主要的成员变量是items,它是一个Object类型的数组用于保存阻塞队列中的元素.其次是takeIn ...

  4. JAVA核心知识点--JDK1.8中的日期处理

    目录 在Java 8中如何处理日期和时间 示例 1.在Java 8中获取今天的日期 示例 2.在Java 8中获取年.月.日信息 示例 3.在Java 8中处理特定日期 示例 4.在Java 8中判断 ...

  5. Java核心知识点 --- 线程中如何创建锁和使用锁 Lock , 设计一个缓存系统

    理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...

  6. 最全最新的的Java核心知识点整理!!! 【推荐】

    前言: 想要文档版的小伙伴们可以私信我领取哦,更加清晰 一目了然 ~ Java核心知识点! 博客整理出来的稍微有点乱~ 目录 目录 -1 JVM - 19 2.1. 线程 - 20 2.2. JVM ...

  7. 字节大牛教你手撕Java学习,Java核心知识点

    线程 线程的启动 实现Runnab1e接口 继承Thread类 实现Callable接口 线程的状态 线程的方法 线程的优先级 守护线程 未捕获异常处理器 并发编程的问题 线程引入开销:上下文切换与内 ...

  8. java获取当前日期的前一天日期,Java核心知识点

    一.分布式架构学习路线图 据统计,人的阅读时间在20分钟以内是能够达到全身心投入的,顾文章单张篇幅以后会尽量缩短,但更新会尽量相应频繁一些. 二.计算机软件发展历史 首先我们了解下计算机软件的发展历史 ...

  9. 第四章Java核心类库_多线程

    第四章第五节Java核心类库_多线程 多线程 一.线程与进程 1.线程与进程 2.线程调度 二.同步与异步&并发与并行 1. 同步与异步 2. 并发与并行 三.继承Thread 1.代码块 2 ...

最新文章

  1. Farseer.net轻量级ORM开源框架 V1.x 入门篇:视图的数据操作
  2. 【Leetcode】33. 搜索旋转排序数组
  3. Kotlin入门(28)Application单例化
  4. centos7下使用rpm包安装clickhouse
  5. 数据结构之单链表的整表创建头插法
  6. Windows Server 2003 Enterprise Edition 下载与安装序列号
  7. 使用帧相似度匹配编写无缝循环视频截取工具
  8. 软件设计师中级-软件工程
  9. 百度SEO站群WordPress企业主题:企业一号 V 1.2.2
  10. 独家 | GAN大盘点,聊聊这些年的生成对抗网络 : LSGAN, WGAN, CGAN, infoGAN, EBGAN, BEGAN, VAE
  11. Redis连接池RedisPool使用
  12. 如何设置vs窗口的属性管理器和解决方案管理器的位置
  13. 2018——幸福都是奋斗出来的
  14. (十四)c#Winform自定义控件-键盘(一)
  15. 微信公众号网页授权,获取用户信息以及openid -- PHP后台
  16. TopCoder入门教程(转载)
  17. 5G全场景时代 战略关键转型期 华为不只要重构想象
  18. 【IEEE/ACM专区】一篇高质量的IEEE/ACM Transaction论文是如何顺利发表的?
  19. Android技术点汇总
  20. 简单的javascript学习01

热门文章

  1. [Angularjs] 第一步开始一个项目
  2. p1198bzoj1012 最大数
  3. 9.1 正则介绍_grep(上)
  4. 第二十九课、主窗口中的状态栏------------------狄泰软件学院
  5. 洛谷 P1118 数字三角形游戏 Label:dfs
  6. oracle新建用户,授权,建表空间语句
  7. MySQL性能优化 分区
  8. MySQL事务(脏读、不可重复读、幻读)
  9. spring mvc和swagger整合
  10. java获取中文拼音首字母