我理解的Java并发基础(六):并发容器和队列

J.U.C包含许多并发常用的容器类工具,比如ConcurrentHashMap、CopyOnWriteArrayList。由与队列Queue在并发中非常重要,并且种类非常多,故本文将队列单独列出,不计算在容器类中。

1,ConcurrentHashMap,并发Map。并发编程中最常用的并发容器。JDK1.8中的底层实现与之前版本不同。在API的使用上和java.lang.HashMap相同。需要注意的是,HashMap支持null作为key,而ConcurrentHashMap不支持,会报空指针异常。ConcurrentHashMap在遍历的时候没有FailFast机制。

2,CopyOnWriteArrayList,支持并发读写的List。在API的使用上和java.lang.ArrayList相同。允许一个线程写的同时多个线程进行读操作。CopyOnWriteArrayList在遍历的时候没有FailFast机制。

队列是并发中经常出现的结构。队列包括阻塞队列BlockingQueue、双端阻塞队列BlockingDequeue、并发队列(非阻塞)ConcurrentLinkedQueue等。遵循FIFO先入先出的原则。

BlockingQueue接口的常用API如下:

boolean add(E e); // 增加元素。如果队列已满,抛IllegalStateException异常
void put(E e) throws InterruptedException; // 增加元素。如果队列已满,则阻塞等待。阻塞期间响应线程中断异常。
boolean offer(E e); // 增加元素。如果队列已满,直接返回false。
boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException // 增加元素。如果队列已满,则阻塞等待一段时间。阻塞期间响应线程中断异常。返回值同offer(E e)

boolean remove(Object o); // 删除指定元素。如果队列发生了改变,则返回true。
E take() throws InterruptedException; // 获取元素。如果队列为空则阻塞等待。阻塞期间响应线程中断异常。
E poll(long timeout, TimeUnit unit) throws InterruptedException; // 指定时间内阻塞等待获取元素。如果队列为空则阻塞等待。阻塞期间响应线程中断异常。
boolean contains(Object o); // 队列中是否包含指定元素

int remainingCapacity(); // 队列还能存放多少个元素,返回值 = 初始化总数 - 以存放个数

BlockingQueue接口的实现类有:ArrayBlockingQueue、DelayQueue、LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue。

1,ArrayBlockingQueue,数组阻塞队列。ArrayBlockingQueue 是一个有界的阻塞队列,构造方法可以指定是否是公平性。其内部实现是将对象放到一个数组里。有界也就意味着,它不能够存储无限多数量的元素。它有一个同一时间能够存储元素数量的上限。你可以在对其初始化的时候设定这个上限,但之后就无法对这个上限进行修改了 (译者注:因为它是基于数组实现的,也就具有数组的特性:一旦初始化,大小就无法修改)。ArrayBlockingQueue 内部以 FIFO(先进先出)的顺序对元素进行存储。队列中的头元素在所有元素之中是放入时间最久的那个,而尾元素则是最短的那个。

2,DelayQueue,延迟队列。DelayQueue 对元素进行持有直到一个特定的延迟到期。注入其中的元素必须实现java.util.concurrent.Delayed接口。给接口继承了java.lang.Comarable比较器接口,具体如下:

public interface Delayed extends Comparable<Delayed> {
    long getDelay(TimeUnit unit);
}

DelayQueue 将会在每个元素的getDelay()方法返回的值的时间段之后才加入到队列中。如果返回的是 0 或者负值,则直接加入到队列中。

3,LinkedBlockingQueue,链表阻塞队列。LinkedBlockingQueue是效率最高的、出镜率最高的阻塞队列,内部以一个链式结构(链接节点)对其元素进行存储。如果需要的话,这一链式结构可以选择一个上限。如果没有定义上限,将使用 Integer.MAX_VALUE 作为上限。

4,PriorityBlockingQueue,优先级队列。PriorityBlockingQueue是一个无界的并发队列。它使用了和ava.util.PriorityQueue 一样的排序规则。所有插入到 PriorityBlockingQueue 的元素必须实现java.lang.Comparable接口,因为元素的优先级比较是通过Comparable接口来完成的。列中元素的排序就取决于你自己的 Comparable 实现。tips:从PriorityBlockingQueue队列返回的Iterator并不能保证元素的遍历是元素的优先级顺序的。

5,SynchronousQueue,同步队列。SynchronousQueue是一个特殊的队列,它的内部同时只能够容纳1个元素。如果该队列已 有一元素的话,试图向队列中插入一个新元素的线程将会阻塞,直到另一个线程将该元素从队列中抽走。同样,如果该队列为空,试图向队列中抽取一个元素的线程将会阻塞,直到另一个线程向队列中插入了一条新的元素。

6,LinkedTransferQueue,无界链表队列。相比于LinkedBlockingQueue,多了tryTransfer和transfer方法。

void transfer(E e) throws InterruptedException // 如果有线程在阻塞等待回去元素,则直接将e传递给等待的线程。如果没有则阻塞等待线程来获取元素。阻塞期间响应线程中断异常。(违反了FIFO原则)
boolean tryTransfer(E e, long timeout, TimeUnit unit)throws InterruptedException // 一段时间内阻塞等待线程获取元素,作用同transfer(E e)。如果超时则返回false。

BlockingDeque是双端阻塞队列接口,允许在队列的两端进元素进行添加和获取。继承类BlockingQueue接口,但是不推荐使用BlockingQueue相关的API。BlockingDeque的常用API如下:

//在头部操作
boolean addFirst(E e); // 同BlockingQueue的add(E e)
void putFirst(E e) throws InterruptedException; // 同BlockingQueue的put(E e)
boolean offerFirst(E e); // 同BlockingQueue的offer(E e)
boolean offerFirst(E e, long timeout, TimeUnit unit) throws InterruptedException // 同BlockingQueue的offer(E e, long timeout, TimeUnit unit)
boolean removeFirstOccurrence(Object o); // 从头部开始删除第一个相同的元素。同BlockingQueue的remove(E e)
E takeFirst() throws InterruptedException; // 同BlockingQueue的take()
E pollFirst(long timeout, TimeUnit unit) throws InterruptedException; // 同BlockingQueue的poll()


// 在尾部操作
boolean addLast(E e); // 同BlockingQueue的add(E e)
void putLast(E e) throws InterruptedException; // 同BlockingQueue的put(E e)
boolean offerLast(E e); // 同BlockingQueue的offer(E e)
boolean offerLast(E e, long timeout, TimeUnit unit) throws InterruptedException // 同BlockingQueue的offer(E e, long timeout, TimeUnit unit)
boolean removeLastOccurrence(Object o); // 从尾部开始删除第一个相同的元素。同BlockingQueue的remove(E e)
E takeLast() throws InterruptedException; // 同BlockingQueue的take()
E pollLast(long timeout, TimeUnit unit) throws InterruptedException; // 同BlockingQueue的poll()

7,LinkedBlockingDeque,链表双端阻塞队列。J.U.C包中BlockingDeque接口的唯一实现类。其实现与LinkedBlockingQueue相同。当链表为空的时候,一个试图从中抽取数据的线程将会阻塞,无论该线程是试图从哪一端抽取数据。建议使用Deque进行多态形式的API操作。

8,ConcurrentLinkedQueue,并发非阻塞安全队列。ConcurrentLinkedQueue实现了Queue接口,是一个基于链表的无界队列,遵循FIFO先进先出原则,使用循环CAS的方式来实现非阻塞并发安全。建议使用Queue进行多态形式的API操作。

猜你喜欢

转载自my.oschina.net/u/3466682/blog/1637748
今日推荐