目录
- 一.并发容器的由来
- 二.常用的Java并发容器
- 1.ConcurrentHashMap
- 2.CopyOnWriteArrayList
- 3.CopyOnWriteArraySet
- 4.ConcurrentLinkedQueue
- 5.ConcurrentLinkedDeque
一.并发容器的由来
在java的集合容器体系中,常用的ArrayList、LinkedList、HashMap等都属于线程不安全的容器。为了适应多线程开发,java首先为我们提供了同步容器
:即通过synchronized关键字修饰整个代码块来保证线程安全。
常见的同步容器有
:Vector、HashTable、Stack等
同步容器保证了线程的安全性,但是synchronized修饰整个代码片极大地降低了程序运行的效率,于是就有了效率更高,同时保证线程安全的并发容器
。
并发容器通过锁分段技术和CAS算法( Compare And Swap)保证线程安全和运行效率。
锁分段技术
即仅仅在需要操作的位置进行同步,对于其他的部分则允许多线程并发执行。
CAS算法原理图解
:
二.常用的Java并发容器
java并发容器都在java.util.concurrent包下:
1.ConcurrentHashMap
做为并发版的HashMap
,其底层结构依然是哈希表结构。在jdk1.7
版本中ConcurrentHashMap依靠锁分段技术
实现并发编程,而在jdk1.8
版本则是采用CAS算法
实现。**
2.CopyOnWriteArrayList
做为并发版的ArrayList
,底层结构也是数组。但与ArrayList不同的是,CopyOnWriteArrayList的底层数组加上了Volatile关键字,以保证可见性和有序性。
实现原理
:对读取操作不加锁限制,只对写(增删改)操作加锁,从而在保证一定线程安全的条件下同时提高了效率。因此CopyOnWriteArrayList读出来的数据有可能不是最新的数据。
正像CopyOnWriteArrayList命名的那样:CopyOnWrite
,在新增或者删除元素时CopyOnWriteArrayList都是复制一个新的数组进行操作,然后再用这个新数组替换原来的数组。
3.CopyOnWriteArraySet
HashSet
的并发版本,底层基于CopyOnWriteArrayList实现
。由于本身是做为HashSet的并发版本,所以内部元素也不允许重复。
当CopyOnWriteArraySet调用add方法时,将会调用CopyOnWriteArrayList的addIfAbsent
方法遍历数组,判断待加入元素是否已存在。如果已经存在,返回false;否则将元素插入数组末尾并返回true。
public boolean add(E e) {
return this.al.addIfAbsent(e);
}
public boolean addIfAbsent(E e) {
Object[] snapshot = this.getArray();
return indexOfRange(e, snapshot, 0, snapshot.length) < 0 && this.addIfAbsent(e, snapshot);
}
private boolean addIfAbsent(E e, Object[] snapshot) {
synchronized(this.lock) {
Object[] current = this.getArray();
int len = current.length;
if (snapshot != current) {
int common = Math.min(snapshot.length, len);
for(int i = 0; i < common; ++i) {
if (current[i] != snapshot[i] && Objects.equals(e, current[i])) {
return false;
}
}
if (indexOfRange(e, current, common, len) >= 0) {
return false;
}
}
Object[] newElements = Arrays.copyOf(current, len + 1);
newElements[len] = e;
this.setArray(newElements);
return true;
}
}
4.ConcurrentLinkedQueue
基于单向链表实现的FIFO(First Input First Output)队列,做为Queue的并发版本。
5.ConcurrentLinkedDeque
基于双向链表实现的并发队列,既可以先进先出,也可以先进后出。