文档章节

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

bfleeee
 bfleeee
发布于 2014/06/06 16:24
字数 672
阅读 7059
收藏 11

在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中线程池,你真的会用吗?

在《深入源码分析Java线程池的实现原理》这篇文章中,我们介绍过了Java中线程池的常见用法以及基本原理。 在文中有这样一段描述: 可以通过Executors静态工厂构建线程池,但一般不建议这样使...

HollisChuang's Blog
2018/10/27
0
0
【死磕Java并发】—– 死磕 Java 并发精品合集

【死磕 Java 并发】系列是 LZ 在 2017 年写的第一个死磕系列,一直没有做一个合集,这篇博客则是将整个系列做一个概览。 先来一个总览图: 【高清图,请关注“Java技术驿站”公众号,回复:脑...

chenssy
2018/07/22
0
0
Java并发编程利用 Condition 实现阻塞队列

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

行走在旅途中
2017/11/07
0
0
Java中线程池,你真的了解会用吗

在《 深入源码分析Java线程池的实现原理 》这篇文章中,我们介绍过了Java中线程池的常见用法以及基本原理。 在文中有这样一段描述: 可以通过Executors静态工厂构建线程池,但一般不建议这样...

小刀爱编程
2018/10/31
0
0
在Java中使用协程(Coroutine)

转自:http://bluedavy.com/?p=4 在讲到具体内容之前,不能不先讲下Coroutine的一些背景知识,来先具体了解下什么是Coroutine。 1. 背景知识 现在的操作系统都是支持多任务的,多任务可通过多...

红薯
2010/05/02
1K
2

没有更多内容

加载失败,请刷新页面

加载更多

开始看《Java学习笔记》

虽然书买了很久,但一直没看。这其中也写过一些Java程序,但都是基于IDE的帮助和对C#的理解来写的,感觉不踏实。 林信良的书写得蛮好的,能够帮助打好基础,看得出作者是比较用心的。 第1章概...

max佩恩
昨天
9
0
Redux 三大原则

1.单一数据源 在传统的MVC架构中,我们可以根据需要创建无数个Model,而Model之间可以互相监听、触发事件甚至循环或嵌套触发事件,这些在Redux中都是不被允许的。 因为在Redux的思想里,一个...

wenxingjun
昨天
6
0
跟我学Spring Cloud(Finchley版)-12-微服务容错三板斧

至此,我们已实现服务发现、负载均衡,同时,使用Feign也实现了良好的远程调用——我们的代码是可读、可维护的。理论上,我们现在已经能构建一个不错的分布式应用了,但微服务之间是通过网络...

周立_ITMuch
昨天
4
0
XML

学习目标  能够说出XML的作用  能够编写XML文档声明  能够编写符合语法的XML  能够通过DTD约束编写XML文档  能够通过Schema约束编写XML文档  能够通过Dom4j解析XML文档 第1章 xm...

stars永恒
昨天
2
0
RabbitMQ学习(2)

1. 生产者客户端 void basicPublish(String exchange, String routingKey, boolean mandatory, boolean immediate, BasicProperties props, byte[] body) 1. 在生产者客户端发送消息时,首先......

江左煤郎
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部