concurrenthashmap

Java容器笔记(四):认识并发容器类

2017-05-28  本文已影响65人  maxwellyue

对于线程安全和并发:线程安全并不一定适合并发(性能还要好),要根据应用场景选用最合适的容器类。

一、历史

synchronized_methods.png

(1)根据具体场景进行设计,尽量避免使用锁,提高容器的并发访问性。
(2)并发容器定义了一些线程安全的复合操作。
(3)并发容器在迭代时,可以不封闭在synchronized中。但是未必每次看到的都是"最新的、当前的"数据。如果说将迭代操作包装在synchronized中,可以达到"串行"的并发安全性,那么并发容器的迭代达到了"脏读"。

可以通过下图简单了解concurrent中关于容器类的接口和类:


Concurrent.png

二、并发容器

2.1 接口

A Map providing thread safety and atomicity guarantees.
Memory consistency effects:
As with other concurrent collections, 
actions in a thread prior to placing an object into a ConcurrentMap as a key or value 
happen-before
actions subsequent to the access or removal of that object from the ConcurrentMap in another thread.
A Queue that additionally supports operations:
wait for the queue to become non-empty when retrieving an element, 
and wait for space to become available in the queue when storing an element.

阻塞队列的方法有四种形式--当操作不能立即得到满足,但可能在未来某一时刻被满足的时候,有四种不同的方式来处理:
a.抛出异常
b.返回特殊的值(null或false,取决与具体的操作)
c.无期限地阻塞当前线程,直到该操作成功
d.仅在指定的最大时长内阻塞,过后还不成功就放弃

BlockingQueue methods come in four forms, with different ways of handling operations 
that cannot be satisfied immediately, but may be satisfied at some point in the future:
 * one throws an exception, 
 * the second returns a special value (either null or  false, depending on the operation), 
 * the third blocks the current thread indefinitely until the operation can succeed,
 * and the fourth blocks for only a given maximum time limit before giving up. 

阻塞队列主要是为生产者-消费者模型设计,但也支持Collection接口,所以它也可以使用remove(x)来移除任意一个元素,但这种操作通常效率不高,偶尔使用时可以的,比如当一个队列消息被取消的时候。

BlockingQueue implementations are designed to be usedprimarily for producer-consumer queues, 
but additionally support the java.util.Collection interface.  
So, for example, it is possible to remove an arbitrary element from a queue using remove(x). 
However, such operations are in general not performed very efficiently, 
and are intended for only occasional use, 
such as when a queued message is cancelled.

阻塞队列的实现类是线程安全的。所有的队列方法可以原子地达到它们的效果:使用内部锁或者其他形式的并发控制。但是,对于批量集合操作,如addAllcontainsAllretainAllremoveAll并不是原子性的(除非另有规定)。所以,像addAll(c)这个操作可能会抛出异常而失败(因为并没有将c中的所有元素都加进来)

BlockingQueue implementations are thread-safe.  
All queuing methods achieve their effects atomically 
using internal locks or other forms of concurrency control. 
However, the bulk Collection operations addAll,containsAll,  retainAll and removeAll 
are not necessarily performed atomically unless specified otherwise in an implementation. 
So it is possible, for example, for addAll(c) to fail (throwing an exception) 
after adding only some of the elements in  c.

2.2 实现类

通过上面的图可以知道,concurrent包中的并发容器主要可以分为:

2.2.1 CopyOnWrite容器

该部分内容(概念、应用场景、缺点)摘抄自JAVA中的COPYONWRITE容器</br>
Copy-On-Write简称COW,是一种用于程序设计中的优化策略。其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略。

//add的时候,使用重入锁,保证只有一个线程在修改
public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
}
//get并未使用任何锁,所以在一个线程add的同时,其他线程均可以进行get操作
public E get(int index) {
        return get(getArray(), index);
}

这些特性也几乎是CopyOnWrite容器的特性。

2.2.2 ConcurrentMap的实现类

2.2.3 阻塞队列

方法/方式处理 抛出异常 返回特殊值 一直阻塞 超时退出
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
检查 element() peek() 不可用 不可用
①如果队列已满:
使用add(e)添加元素,则抛出IllegalStateException("Queue full")异常;
使用offer(e)添加元素,则返回false;
使用put(e)添加元素,则当前线程会一直阻塞,直到队列中出现空位或响应中断退出;
使用offer(e, time, unit)添加元素,则当前线程会阻塞一定时间,超时后如果还是满,则返回false,如果在超时前放入成功,则返回true

②如果队列为空:
使用remove()移除元素,则抛出NoSuchElementException异常;
使用poll()移除元素,则返回null;
使用take()移除元素,则当前线程会一直阻塞,直到队列中有元素插入或响应中断退出;
使用poll(time, unit)移除元素,则当前线程会阻塞一定时间,超时后如果还是为空,则返回null,如果在超时前有元素插入,则返回插入的这个元素

2.2.4 其他实现类(待补充)


参考

未一一列出

20171210更新:增加阻塞队列的介绍
20171211更新:增加CopyOnWrite容器的add和get方法源码及说明
20171220更新:更新阻塞队列中ArrayBlockingQueue和LinkedBlockingQueue的介绍

上一篇下一篇

猜你喜欢

热点阅读