文档章节

Java可阻塞队列的两种实现方式

bfleeee
 bfleeee
发布于 2014/06/06 16:24
字数 672
阅读 6972
收藏 11
点赞 0
评论 0

在Java中,对于Lock和Condition可以理解为对传统的synchronized和wait/notify机制的替代。

wait/notify有个限制,调用wait/notify的线程必须持有对象的锁。

This method should only be called by a thread that is the owner of this object's monitor. See the notify method for a description of the ways in which a thread can become the owner of a monitor.

Throws:

IllegalMonitorStateException - if the current thread is not the owner of this object's monitor.

通常使用wait/notify的代码是这个样子的:

synchronized (obj) {
         while (<condition does not hold>)
             obj.wait();
         ... // Perform action appropriate to condition
     }

在Condition接口的javadoc中,有一个经典的Condition例子,用Condition实现了一个可阻塞队列。这里仿照javadoc简单实现了一个可阻塞队列。为了简单,没有进行try/catch,同时加入了一些注释。

<!-- lang: java -->
public class BoundedBuffer {
    final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();

final Object[] items = new Object[2]; // 阻塞队列
int putptr, takeptr, count;

public void put(Object x) throws InterruptedException {
	System.out.println("进入put");
	lock.lock();
	System.out.println("put lock 锁住");
	try {
		while (count == items.length) { // 如果队列满了,notFull就一直等待
			System.out.println("put notFull 等待");
			notFull.await(); // 调用await的意思取反,及not notFull -> Full
		}
		items[putptr] = x; // 终于可以插入队列
		if (++putptr == items.length)
			putptr = 0; // 如果下标到达数组边界,循环下标置为0
		++count;
		System.out.println("put notEmpty 唤醒");
		notEmpty.signal(); // 唤醒notEmpty
	} finally {
		System.out.println("put lock 解锁");
		lock.unlock();
	}
}

public Object take() throws InterruptedException {
	lock.lock();
	System.out.println("take lock 锁住");
	try {
		while (count == 0) {
			System.out.println("take notEmpty 等待");
			notEmpty.await();
		}
		Object x = items[takeptr];
		if (++takeptr == items.length)
			takeptr = 0;
		--count;
		System.out.println("take notFull 唤醒");
		notFull.signal();
		return x;
	} finally {
		lock.unlock();
		System.out.println("take lock 解锁");
	}
}

public static void main(String[] args) throws InterruptedException {
	final BoundedBuffer bb = new BoundedBuffer();
	System.out.println(Thread.currentThread()+","+bb);
	
	new Thread(new Runnable() {
		@Override
		public void run() {
			try {
				Thread.sleep(1000);
				System.out.println(Thread.currentThread()+","+bb);
				bb.put("xx");
				bb.put("yy");
				bb.put("zz");
                                    bb.put("zz");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}).start();
	bb.take();
}
}

如果不使用JUC,大概是这样的:

<!-- lang: java -->
public class BoundedBuffer_Synchronized {
private Object[] items = new Object[2];
private Object notEmpty = new Object();
private Object notFull = new Object();
int count,putidx,takeidx;

public  void put(Object obj) throws InterruptedException{
	synchronized(notFull){
		while(count == items.length){
			notFull.wait();
		}
	}
	items[putidx] = obj;
	if(++putidx == items.length){
		putidx = 0;
	}
	count ++;
	synchronized (notEmpty) {
		notEmpty.notify();
	}
}
public Object take() throws InterruptedException{
	synchronized(notEmpty){
		while(count == 0){ // 啥也没有呢 取啥
			notEmpty.wait();
		}
	}
	Object x = items[takeidx];
	System.out.println("取第"+takeidx+"个元素"+x);
	if(++takeidx == items.length){
		takeidx = 0; 
	}
	count --;
	synchronized (notFull) {
		notFull.notify();
	}
	return x;
}
public static void main(String[] args) throws InterruptedException {
	final BoundedBuffer_Synchronized bb = new BoundedBuffer_Synchronized();
	System.out.println(Thread.currentThread()+","+bb);
	
	new Thread(new Runnable() {
		@Override
		public void run() {
			try {
				Thread.sleep(1000);
				System.out.println(Thread.currentThread()+","+bb);
				bb.put("xx");
				bb.put("yy");
				bb.put("zz");
				bb.put("zz");
				bb.put("zz");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}).start();
	bb.take();
	bb.take();
}
}

从功能上来讲,两者实现了可阻塞队列的基本业务需求。Condition是配合Lock使用的,而wait/notify是配合synchronized使用的。比较两种实现方式,其实就是比较Lock和synchronized两种同步机制的区别。关于这方面,可以参考Java 理论与实践: JDK 5.0 中更灵活、更具可伸缩性的锁定机制

© 著作权归作者所有

共有 人打赏支持
bfleeee

bfleeee

粉丝 12
博文 33
码字总数 26316
作品 0
海淀
高级程序员
Java并发编程利用 Condition 实现阻塞队列

什么是阻塞队列 BlockingQueue 队列是一种数据结构,它的特点是先进先出(First In First Out),它有两个基本操作:在队列尾部加入一个元素,从队列头部移除一个元素。队列在多线程应用中,...

行走在旅途中
2017/11/07
0
0
Java 并发工具包 java.util.concurrent 用户指南

译序 本指南根据 Jakob Jenkov 最新博客翻译,请随时关注博客更新:http://tutorials.jenkov.com/java-util-concurrent/index.html。 本指南已做成中英文对照阅读版的 pdf 文档,有兴趣的朋友...

pior
2015/10/26
0
0
2018年Java编程学习面试最全知识点总结

Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互...

Java小辰
05/14
0
0
JDK容器学习之Queue: ArrayBlockingQueue

基于数组阻塞队列 ArrayBlockingQueue 前面学习了基于数组的非阻塞双端队列,其内部维护一个数组和指向队列头和队列尾索引的两个成员变量;本篇则探究下基于数组的阻塞队列是什么样的数据结构...

小灰灰Blog
2017/11/02
0
0
读书笔记之《Java并发编程的艺术》-并发编程容器和框架(重要)

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
0
1
Java多线程之线程安全队列Queue

在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列。Java提供的线程安全的Queue可以分为阻塞队列和非阻塞队列,其中阻塞队列的典型例子是BlockingQueue,非阻塞...

ljrapple
2014/09/05
0
0
聊聊并发(七)Java中的阻塞队列

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。阻塞队列常用...

陶邦仁
2015/03/20
0
0
Android ThreadLocal+PriorityQueue构建多线程队列

一、消息队列 Android中使用了很多消息队列,如Intent,Handler,BroadcastReceiver等。使用消息队列的目的是防止线程阻塞并且将不能及时执行的任务缓存起来,从而提高系统的运行效率。 为了使...

IamOkay
2014/11/03
0
0
java并发编程(六): 取消与关闭

取消与关闭: 如何正确,安全地取消或关闭任务。 任务取消: 若外部代码能在某个操作正常完成之前将其置入“完成”状态,则还操作是可取消的。 取消操作的原因: 1. 用户请求取消。 2. 有时间...

ihaolin
2014/03/30
0
0
Java多线程学习(四)等待/通知(wait/notify)机制

系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Ja...

一只蜗牛呀
04/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Java基础——异常

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。 异常处理: 可以挖很多个陷阱,但是不要都是一样...

凯哥学堂
4分钟前
0
0
180723-Quick-Task 动态脚本支持框架之结构设计篇

Quick-Task 动态脚本支持框架之结构设计篇 相关博文: 180702-QuickTask动态脚本支持框架整体介绍篇 180719-Quick-Task 动态脚本支持框架之使用介绍篇 前面两篇博文,主要是整体介绍和如何使用...

小灰灰Blog
8分钟前
0
0
SBT 常用开发技巧

SBT 一直以来都是 Scala 开发者不可言说的痛,最主要的原因就是官方文档维护质量较差,没有经过系统的、循序渐进式的整理,导致初学者入门门槛较高。虽然也有其它构建工具可以选择(例如 Mill...

joymufeng
12分钟前
0
0
HBase in Practice - 性能、监控及问题解决

李钰(社区ID:Yu Li),阿里巴巴计算平台事业部高级技术专家,HBase开源社区PMC&committer。开源技术爱好者,主要关注分布式系统设计、大数据基础平台建设等领域。连续4年基于HBase/HDFS设计和...

中国HBase技术社区
13分钟前
1
0
ES18-JAVA API 批量操作

1.批量查询 Multi Get API public static void multiGet() {// 批量查询MultiGetResponse response = getClient().prepareMultiGet().add("my_person", "my_index", "1")// 查......

贾峰uk
17分钟前
0
0
SpringBoot2.0使用health

1,引入actuator <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency> 2,application.properties ......

暗中观察
24分钟前
0
0
阿里巴巴Java开发规约

###编程规约 命名风格 【强制】代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束 【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。...

简心
29分钟前
0
0
如何用TypeScript来创建一个简单的Web应用

转载地址 如何用TypeScript来创建一个简单的Web应用 安装TypeScript 获取TypeScript工具的方式: 通过npm(Node.js包管理器) npm install -g typescript 构建你的第一个TypeScript文件 创建...

durban
34分钟前
0
0
分享好友,朋友圈自定义分享链接无效

这个问题是微信6.5.6版本以后,修改了分享规则:分享的连接必须在公众号后台设定的js安全域名内

LM_Mike
51分钟前
0
0
2018年7月23日课程

一、LVS-DR介绍 director分配请求到不同的real server。real server 处理请求后直接回应给用户,这样director负载均衡器仅处理客户机与服务器的一半连接。负载均衡器仅处理一半的连接,避免了...

人在艹木中
55分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部