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 ...
随机推荐
- MySQL管理_数据库启动与关闭
MySQL数据库服务器通常指的的是mysqld,而命令行mysql则是mysql客户端程序,这两个概念通常容易混淆.通常启动mysql服务器即是启动mysqld进程,mysqld启动后,可以通过mys ...
- mpstat, pidstat, iostat和sar
在我们上一篇文章中,我们已经学习了如何去安装和更新sysstat,并且了解了包中的一些实用工具. 今天,我们将会通过一些有趣的实例来学习mpstat, pidstat, iostat和sar等工具,这 ...
- itextSharp 附pdf文件解析
一.PdfObject: pdf对象 ,有9种,对象是按照对象内涵来分的,如果按照对象的使用规则来说,对象又分为间接对象和直接对象.间接对象是PDF中最常用的对象,如前面对象集合里面的,所有对象都是间 ...
- Linux 下没有conio.h 已解决
原文:http://blog.sina.com.cn/s/blog_6a95e00b0100zqvf.html #include <stdio.h>//#include <conio ...
- Python基础篇【第2篇】: Python自定义函数
Python函数 1. 函数定义 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段.函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print ...
- maven部署tomcat项目,403错误解决
maven部署tomcat项目时403错误的解决方法 web模块的pom文件 pom.xml <plugin> <groupId>org.apache.tomcat.maven ...
- Linux 账户信息显示和实现账户安全
一.账户信息显示 1.groups命令 使用groups命令可以显示指定用户账户的组群成员身份. [root@redhat2 ~]# groups --help Usage: groups [OPTI ...
- Flex 加载tiff
gis系统常常要加载tiff,因为好多土地证书,各种文件都是扫描件,如果你是用as来写的前台,怎么加载呢,顺便说下用插件AlternaTIFF也是可以得不过浏览器加载这么多插件是不太好的. 首先TIF ...
- 【练习】flashback基于scn的闪回查询
1.创建表dept1: :: SCOTT@ORA11GR2>create table dept1 as select * from dept; Table created. :: SCOTT@O ...
- 使用jquery获取url以及jquery获取url参数的方法
使用jquery获取url以及使用jquery获取url参数是我们经常要用到的操作 1.jquery获取url很简单,代码如下 1.window.location.href; 其实只是用到了javas ...