Java-SynchronousQueue 阻塞队列小记

在BlockingQueue的子类中有一个SynchronousQueue(同步队列)比较少见,现在做一个简单的介绍,并附加一个简单的例子。

SynchronousQueue --JDK1.6介绍:

public class SynchronousQueue<E>
extends AbstractQueue<E>
implements BlockingQueue<E>, Serializable

一种阻塞队列,其中每个插入操作必须等待另一个线程的对应移除操作 ,反之亦然。同步队列没有任何内部容量,甚至连一个队列的容量都没有。不能在同步队列上进行 peek,因为仅在试图要移除元素时,该元素才存在;除非另一个线程试图移除某个元素,否则也不能(使用任何方法)插入元素;也不能迭代队列,因为其中没有元素可用于迭代。队列的 是尝试添加到队列中的首个已排队插入线程的元素;如果没有这样的已排队线程,则没有可用于移除的元素并且 poll() 将会返回 null。对于其他 Collection 方法(例如 contains),SynchronousQueue 作为一个空
collection。此队列不允许 null 元素。

同步队列类似于 CSP 和 Ada 中使用的 rendezvous 信道。它非常适合于传递性设计,在这种设计中,在一个线程中运行的对象要将某些信息、事件或任务传递给在另一个线程中运行的对象,它就必须与该对象同步。

对于正在等待的生产者和使用者线程而言,此类支持可选的公平排序策略。默认情况下不保证这种排序。但是,使用公平设置为 true 所构造的队列可保证线程以 FIFO 的顺序进行访问。公平通常会降低吞吐量,但是可以减小可变性并避免得不到服务。

此类及其迭代器实现 Collection 和 Iterator 接口的所有可选 方法。

简介及注意点

SynchronousQueue同步队列(哈哈不知准确否)继承了BlockingQueue<E>接口,功能类似于:一直等待,来一个及时处理一个,但不能同事处理两个。比如queue.take()方法会阻塞,一直queue.offer(element)插入一个元素,二插入的元素马上就别queue.take()处理掉。所以它没有容纳元素的能力,isEmpty方法总是返回true,但是给人的感觉像是可以临时容纳一个元素。

另外在创建SynchronousQueue时可以传递一个boolean参数来指定它是否是访问它的线程按遵守FIFO顺序处理,true表示遵守FIFO。

注意:

注意1:它一种阻塞队列,其中每个 put 必须等待一个 take,反之亦然。

同步队列没有任何内部容量,甚至连一个队列的容量都没有。

注意2:它是线程安全的,是阻塞的。

注意3:
 不允许使用 null 元素。

注意4:公平排序策略是指调用put的线程之间,或take的线程之间。 公平排序策略可以查考ArrayBlockingQueue中的公平策略。

注意5:SynchronousQueue的以下方法很有趣:

* iterator() 永远返回空,因为里面没东西。

* peek() 永远返回null。

* put() 往queue放进去一个element以后就一直wait直到有其他thread进来把这个element取走。

* offer() 往queue里放一个element后立即返回,如果碰巧这个element被另一个thread取走了,offer方法返回true,认为offer成功;否则返回false。

* offer(2000, TimeUnit.SECONDS) 往queue里放一个element但是等待指定的时间后才返回,返回的逻辑和offer()方法一样。

* take() 取出并且remove掉queue里的element(认为是在queue里的。。。),取不到东西他会一直等。

* poll() 取出并且remove掉queue里的element(认为是在queue里的。。。),只有到碰巧另外一个线程正在往queue里offer数据或者put数据的时候,该方法才会取到东西。否则立即返回null。

* poll(2000, TimeUnit.SECONDS) 等待指定的时间然后取出并且remove掉queue里的element,其实就是再等其他的thread来往里塞。

* isEmpty()永远是true。

* remainingCapacity() 永远是0。

* remove()和removeAll() 永远是false。


代码示例:

import java.util.Random;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
/**
 * 下面使用SynchronousQueue模拟:
 * 最多只有一个产品的生产者-消费者模型
 *
 * 消费者线程们 逐个请求消费产品
 * 生产者线程们 逐个生产产品。
 *
 * @author maguowei01
 *
 */
public class SynchronousQueueTest {
	public static void main(String[] args) {
                //true保证生产或消费者线程以FIFO的顺序访问。
		SynchronousQueue<Integer> queue = new SynchronousQueue<Integer>(true);
		for (int i = 0; i < 3; ++i) {
			new Customer(queue).start();
		}
		for (int i = 0; i < 3; ++i) {
			new Product(queue).start();
		}
	}
	static class Product extends Thread {
		SynchronousQueue<Integer> queue;
		public Product(SynchronousQueue<Integer> queue) {
			this.queue = queue;
		}
		@Override
		public void run() {
			while (true) {
				int rand = new Random().nextInt(1000);
				System.out.println("Thread Id:" + getId() + "  生产了一个产品:" + rand);
				System.out.println("Thread Id:" + getId() + " 等待两秒后运送出去...");
				try {
					TimeUnit.SECONDS.sleep(2);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				/*
				 * offer()往queue里放一个element后立即返回,如果碰巧这个element被另一个thread取走了,
				 * offer方法返回true,认为offer成功;否则返回false。
				 * 也就是说offer不一定真正的插入的队列中,肯定没成功丢失了
				 */

				// queue.offer(rand);  //注意offer与put方法的区别
				try {
					/*
					 * put()往queue放进去一个element以后就一直wait直到有其他thread进来把这个element取走。
					 */
					queue.put(rand);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	static class Customer extends Thread {
		SynchronousQueue<Integer> queue;
		public Customer(SynchronousQueue<Integer> queue) {
			this.queue = queue;
		}
		@Override
		public void run() {
			while (true) {
				try {
					// 线程运行到queue.take()阻塞,直到Product生产一个产品queue.offer。
					System.out.println("Thread Id:" + getId() + " 消费了一个产品:" + queue.take());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("------------------------------------------");
			}
		}
	}
}

Java-SynchronousQueue 阻塞队列小记,布布扣,bubuko.com

时间: 2024-12-28 00:21:42

Java-SynchronousQueue 阻塞队列小记的相关文章

Java多线程 阻塞队列和并发集合

转载:大关的博客 Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容.在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃.Java为多线程专门提供了特有的线程安全的集合类,通过下面的学习,您需要掌握这些集合的特点是什么,底层实现如何.在何时使用等问题. 3.1 BlockingQueue接口 java阻塞队列应用于生产者消费者模式.消息传递.并行任务执行和相关并发设计的大多数常见使用上下文. BlockingQueue在Queue接口基础上提供了额外

Java中阻塞队列的使用

http://blog.csdn.net/qq_35101189/article/details/56008342 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利.本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景. 认识BlockingQueue阻塞队列,顾名思义,首先它是一个队列,而一个队列在数据结构中所

Java多线程——阻塞队列

现在,通过前几篇的总结,我们对Java多线程已经有所了解了,但是它们都是一些Java并发程序设计基础的底层构建块.对于实际编程来说,我们应该尽可能的远离底层结构.使用那些由并发处理的专业人士实现的较高层次的结构要方便的多,安全的多. 阻塞队列 对于许多线程问题.可以通过使用一个或多个队列以优雅且安全的方式将其形式化.生产者线程向队列插入元素,消费者线程则取出他们.使用队列,可以安全地从一个线程向另一个线程传递数据. 阻塞队列的方法 方法 正常动作 特殊情况下动作 add 添加一个元素 如果队列满

java 可伸缩阻塞队列实现

最近一年多写的最虐心的代码.必须好好复习java并发了.搞了一晚上终于测试都跑通过了,特此纪念,以资鼓励! import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.

java 多线程阻塞队列 与 阻塞方法与和非阻塞方法

Queue是什么 队列,是一种数据结构.除了优先级队列和LIFO队列外,队列都是以FIFO(先进先出)的方式对各个元素进行排序的.无论使用哪种排序方式,队列的头都是调用remove()或poll()移除元素的.在FIFO队列中,所有新元素都插入队列的末尾.队列都是线程安全的,内部已经实现安全措施,不用我们担心 Queue中的方法 Queue中的方法不难理解,6个,每2对是一个也就是总共3对.看一下JDK API就知道了: 注意一点就好,Queue通常不允许插入Null,尽管某些实现(比如Link

29、java中阻塞队列

阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素.同样,试图往已满的阻塞队列中添加新元素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来,如从队列中移除一个或者多个元素,或者完全清空队列,下图展示了如何通过阻塞队列来合作: 线程1往阻塞队列中添加元素,而线程2从阻塞队列中移除元素 使用BlockingQueue的关键技术点如

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

方式一:/** * 使用非阻塞队列PriorityQueue及wait/notify方法实现一个阻塞队列**/class MyBlockingQueue {    public final static int queueSize = 10;    public static final PriorityQueue<Integer> queue = new PriorityQueue();}    class Producer extends Thread {    public void r

JAVA实现阻塞队列

package 多线程并发; import java.util.Stack; /** * Created by z84102272 on 2018/7/17. */ public class BlockQueueImpl { private final static Object pushLock = new Object(); //push的锁 private final static Object popLock = new Object(); //pop的锁 private Stack<O

java 阻塞队列 LinkedBlockingQueue ArrayBlockingQueue 分析

BlockingQueue是阻塞队列接口类,该接口继承了Queue接口 BlockingQueue实现类常见的有以下几种. ArrayBlockingQueue:ArrayBlockingQueue 是一个有界的阻塞队列,其内部实现是将对象放到一个数组里.有界也就意味着,它不能够存储无限多数量的元素.它有一个同一时间能够存储元素数量的上限.你可以在对其初始化的时候设定这个上限,但之后就无法对这个上限进行修改了(译者注:因为它是基于数组实现的,也就具有数组的特性:一旦初始化,大小就无法修改). D