Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍
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. //方式3
public 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介绍的更多相关文章
- Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统
理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...
- java核心知识点学习----多线程间的数据共享和对象独立,ThreadLocal详解
线程内的数据共享与对象独立,举例:张三给李四转钱,开启A线程去执行转钱这个动作,刚好同时王五给赵六转钱,开启B线程去执行转钱,因为是调用的同样一个动作或者说对象,所以如果不能保证线程间的对象独立,那么 ...
- Java核心知识点学习----多线程 倒计时记数器CountDownLatch和数据交换的Exchanger
本文将要介绍的内容都是Java5中的新特性,一个是倒计时记数器---CountDownLatch,另一个是用于线程间数据交换的Exchanger. 一.CountDownLatch 1.什么是Coun ...
- Java核心知识点学习----线程中的Semaphore学习,公共厕所排队策略
1.什么是Semaphore? A counting semaphore. Conceptually, a semaphore maintains a set of permits. Each acq ...
- java核心知识点学习----多线程并发之线程同步
1.什么是线程同步? 多线程编程是很有趣的事情,它很容易出现"错误情况",这种情况不是由编码造成的,它是由系统的线程调度造成的,当使用多个线程来访问同一个数据时,很容易出现&quo ...
- Java核心知识点学习----多线程并发之线程间的通信,notify,wait
1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...
- java核心知识点学习----多线程间的数据共享的几种实现方式比较
需求:设计4个线程,其中两个线程每次对j增加1,另外两个线程对j减少1. 实现数据共享的几种方式比较: 1.使用同一个runnable对象 如果每个线程执行的代码相同,那么可以使用同一个runnabl ...
- Java核心知识点学习----使用Condition控制线程通信
一.需求 实现线程间的通信,主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次. 即:A->B->C---A->B->C---A-> ...
- Java中的阻塞队列-ArrayBlockingQueue(一)
最近在看一些java基础的东西,看到了队列这章,打算对复习的一些知识点做一个笔记,也算是对自己思路的一个整理,本章先聊聊java中的阻塞队列 参考文章: http://ifeve.com/java-b ...
随机推荐
- Mustache 使用心得总结
Mustache 使用心得总结 前言: 之前的一个项目里面就有用到这个前台的渲染模版,当时挺忙的也没时间抽空总结一下,刚好上周项目里又用到这个轻量型的渲染模版,真心感觉很好用,因此就总结一下使用心得, ...
- Hive操作表部分总结
创建表: create table tableName(time INT,userid BIGINT,url STRING,ip STRING COMMENT 'IP Address of the U ...
- Spark ML 文本的分类
最近一直在研究Spark的分类算法,因为我们是做日志文本分类,在官网和各大网站一直没找到相应的Demo,经过1个多月的研究,终于有点成效. val sparkConf = new SparkConf( ...
- 纯CSS实现圆形进度条
CSS的优点在于的可以随意组合HTML元素来实现许多中效果,这儿我将使用CSS来实现一个运行进度条,效果如下: 思路是用两个div来作为进度条外观,表示进度的div和外面div宽度和高度保持一致,并是 ...
- EBS R12重启后无法进入登录页面
应用启动正常,但无法进入登录页面: The webpage cannot be found HTTP 404 ... No known changes had been made and the Mi ...
- 在linux下获取帮助
1.使用man手册页 man是一种显示Unix/Linux在线手册的命令.可以用来查看命令.函数或文件的帮助手册,另外它还可以显示一些gzip压缩格式的文件. 读者在遇到不懂的命令时,可以用man查看 ...
- Could not load file using Ranorex runtime : General Questions
如果你将编译好的bin文件夹复制到另一个未安装Ranorex程序的电脑上运行遇到如下错误信息 Could not load file or assembly 'Ranorex.Core, Versio ...
- 关于ILDASM.EXE的知识整理
因为现在用的VS2010,发现,这个工具自己就带着ILDASM.EXE这个反编译工具 具体的查找方式为: C:\Program Files\Microsoft SDKS\Windows\V7.0\bi ...
- 2016-08-15:从YUV420P中提取指定大小区域
typedef struct { int width; int height; }SizeInfo; typedef struct { int x; int y; int width; int hei ...
- Ubuntu 12.10使用apt安装Oracle/Sun JDK
apt-get install python-software-properties sudo add-apt-repository ppa:webupd8team/java sudo apt-get ...