JDK容器与并发—Queue—Interface

框架概览

接口介绍

Queue

俗称队列,其设计目标是存储处理前的元素。在Collection基础上,新增了入队、出队、访问队首元素的方法:

1)Queue有两套功能相同的方法:add、remove、element分别为入队、出队、访问队首元素方法的抛出异常版本;offer、poll、peek则为返回特殊值的版本:

2)offer在有界队列中常用,当队列已满时,元素入队会返回false而不是抛出异常,因为这一般当作正常情况;

3)按照元素出入队顺序可分为:FIFO队列、LIFO队列、优先级队列,这三种队列的一个共同点是:remove、poll返回的元素都是队首元素:

4)Queue一般不自行实现基于元素的equals、hashCode方法,因为在队列中可能存在多个相等的元素,但是它们的顺序是不同的,“顺序”在队列中是很特别的。

BlockingQueue

俗称阻塞队列,支持删除时一直等到有元素,增加时一直等到队列有容量空间:

1)其设计主要目标是用作生产者—消费者队列

2)BlockingQueue实现类是线程安全的,其方法采用锁或其他形式并发(如lock-free、wait-free等)实现原子性,对于批量操作addAll、ContainsAll、retainAll、removeAll不一定是原子的,除非特别实现;

3)其存在4种不同版本的操作:

4)BlockingQueue有内部容量限制,可采用remainingCapacity()查看,若无则为Integer.MAX_VALUE;

5)不支持null元素,增加null会抛出NullPointerException,null用于给poll操作检查是否失败;

6)内存一致性原则:先于“添加元素到BlockingQeque队列”的操作happens-before后于“获取或删除该元素”的操作;

7)生产者—消费者应用场景,在多个生产者、消费者线程下线程安全:

class Producer implements Runnable {
	private final BlockingQueue queue;
	Producer(BlockingQueue q) { queue = q; }
	public void run() {
		try {
			while (true) { queue.put(produce()); }
		} catch (InterruptedException ex) { ... handle ...}
	}
	Object produce() { ... }
}

class Consumer implements Runnable {
	private final BlockingQueue queue;
	Consumer(BlockingQueue q) { queue = q; }
	public void run() {
		try {
			while (true) { consume(queue.take()); }
		} catch (InterruptedException ex) { ... handle ...}
	}
	void consume(Object x) { ... }
}

class Setup {
	void main() {
		BlockingQueue q = new SomeQueueImplementation();
		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();
	}
}

Deque

俗称双端队列,支持有界容量、无界容量。

Deque不支持List的索引访问方式;尽管允许null元素,但尽量避免使用,null用做方法的特殊值;一般不定义基于元素的equals、hashCode方法,而采用Object的原生方法。

自有方法:

用作FIFO等效方法:

用作LIFO(Stack)等效方法:

BlockingDeque

Blocking+Deque

内存一致性原则:先于“添加元素到BlockingDeque队列”的操作happens-before后于“获取或删除该元素”的操作;

TransferQueue

Blocking+Transfer,俗称传输队列,支持生产者等待消费者获取元素。

时间: 2024-10-12 16:48:06

JDK容器与并发—Queue—Interface的相关文章

JDK容器与并发—数据结构

基础数据结构 数组 对于n个元素的数组可如下表示: 数组在初始化时需要明确指定长度,一旦成功完成后,该数组所占用的内存空间就固定下来,一般是连续分配的内存空间.例如对于数组array,可以通过array[i]来访问或设置数组元素值(其中i为索引,对于长度为n的数组,第一个索引值为0,最后一个为n-1). 优点:随机访问效率高,时间复杂度为O(1):缺点:长度固定,不能动态增加.删除元素. 单链表 对于n个节点的单链表可以如下表示: 其类可如下表示: class Node<E> { E item

JDK容器与并发—Map—ConcurrentSkipListMap

概述 基于跳表实现的ConcurrentNavigableMap. 1)containsKey.get.put.remove等操作的平均时间复杂度为log(n):size非固定时间操作,因异步特性,需要遍历所有节点才能确定size,且可能不是正确的值如果遍历过程中有修改:批量操作:putAll.equals.toArray.containsValue.clear非原子性. 2)增删改查操作并发线程安全: 3)迭代器是弱一致性的:map创建时或之后某个时间点的,不抛出ConcurrentModif

JDK容器与并发—Map—ConcurrentHashMap

概述 线程安全的HashMap版本. 1)基本思想:将整个大的hash table进一步细分成小的hash table,即Segment: 2)读不用加锁:写操作在所在的Segmenet上加锁,而不是整个HashMap,Hashtable就是所有方法竞争Hashtable上的锁,导致并发效率低: 3)采用懒构造segment(除了segments[0]),以减少初始化内存.Unsafe类实现了AtomicReferenceArrays的功能,但减少了间接引用的程度.对Segment.table元

并发编程(9):同步类容器与并发类容器

1.同步类容器 同步类容器都是线程安全的,但在某些场景下可能需要加锁来保护复合操作. 复合操作,如: 迭代(反复访问元素,遍历完容器中所有的元素) 跳转(根据指定的顺序找到当前元素的下一个元素) 条件运算 这些复合操作在多线程并发的修改容器时,可能会表现出意外的行为,最经典的就是ConcurrentModificationException,原因是当容器迭代的过程中,被并发的修改了内容,这是由于早期迭代器设计的时候并没有考虑并发修改的问题. 同步类容器:如古老的Vector.HashTble.这

Java学习笔记—多线程(同步容器和并发容器)

简述同步容器与并发容器 在Java并发编程中,经常听到同步容器.并发容器之说,那什么是同步容器与并发容器呢?同步容器可以简单地理解为通过synchronized来实现同步的容器,比如Vector.Hashtable以及SynchronizedList等容器,如果有多个线程调用同步容器的方法,它们将会串行执行. 可以通过查看Vector.Hashtable等同步容器的实现代码,可以看到这些容器实现线程安全的方式就是将它们的状态封装起来,并在需要同步的方法上加上关键字synchronized,但在某

并发容器(一)同步容器 与 并发容器

一.同步容器 同步容器包括两类: Vector.Hashtable.Stack 同步的封装器类由 Collections.synchronizedXXX 等工厂方法创建的.(JDK1.2加入) ??这些类实现线程安全的方式是:将他们的状态封装起来,并对每个公有方法都进行同步,使得每一次只有一个线程能访问容器的状态. 同步容器类的出现是为了解决 Collection.Map 不能同步,线程不安全的问题. 同步容器类的问题 ??同步容器类都是线程安全的,但不是绝对的线程安全 (所谓线程安全仅仅是在每

Java并发-从同步容器到并发容器

引言 容器是Java基础类库中使用频率最高的一部分,Java集合包中提供了大量的容器类来帮组我们简化开发,我前面的文章中对Java集合包中的关键容器进行过一个系列的分析,但这些集合类都是非线程安全的,即在多线程的环境下,都需要其他额外的手段来保证数据的正确性,最简单的就是通过synchronized关键字将所有使用到非线程安全的容器代码全部同步执行.这种方式虽然可以达到线程安全的目的,但存在几个明显的问题:首先编码上存在一定的复杂性,相关的代码段都需要添加锁.其次这种一刀切的做法在高并发情况下性

JDK容器 Vector源码剖析

今天开始,看一下JDK容器源码,这要比比其他jdk源码要简单的多,大部分都能看的懂,这里就不在多言.重点是: Vector的扩容机制: 若自动增长量小于0,则新长度为当前长度的两倍,否则为旧容量+capacityIncrement 和线程安全的原因就是因为使用了同步控制 synchronized. public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Clonea

qt容器在并发时需要注意的地方

最近用tbb和qt写了一个延时摄影后期控制镜头的工具,主要就是扫描目录下所有图片,按照给定参数截取图片中某区域并另存,模拟镜头摆动. 扫描后的图片路径保存在qlist内,作为只读数据,交由tbb的parellel_for处理.tbb并行对qlist每个元素内的路径对应的图片进行读取,裁剪,另存操作(磁盘是ssd,这个程序在8线程的机器上,可令cpu满负荷).理想是美好的,现实是残酷的. 前提,qlist(不光qlist了,qt很多数据结构都)实现了copy on write,qlist的索引操作