ArrayList -> CopyOnWriteArrayList
当有新元素添加到CopyOnWriteArrayList的时候,先从原有的数组里拷贝一份出来,然后在新的数组上做些操作,写完之后再将原来的数组指向新的数组 。整个的add操作都是在写的保护下进行的,避免在多线程并发下进行add操作时复制出多个数组出来,把数据搞乱
缺点:消耗内存; 不能用于实时读的操作
适合读多写少的场景
设计思想:读写分离、最终结果一致性
读操作时在原数组上进行,不需要加锁,写操作时加锁
add操作加锁源码
/**
* Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
*
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
synchronized (lock) {
Object[] elements = getArray();
int len = elements.length;
if (index > len || index < 0)
throw new IndexOutOfBoundsException(outOfBounds(index, len));
Object[] newElements;
int numMoved = len - index;
if (numMoved == 0)
newElements = Arrays.copyOf(elements, len + 1);
else {
newElements = new Object[len + 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index, newElements, index + 1,
numMoved);
}
newElements[index] = element;
setArray(newElements);
}
}
get不加锁源码
/**
* {@inheritDoc}
*
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
return elementAt(getArray(), index);
}
HashSet -> CopyOnWriteArraySet
线程安全的,底层实现是用到了CopyOnWriteArrayList
,适合于大小较小的list集合,只读大于写操作的场景,因为需要复制整个数组,所以开销,迭代器不支持remove操作
TreeSet -> ConcurrentSkipListSet
支持自然排序,基于Map集合,多个线程可以并发执行add,remove等操作,但是对于批量操作如addAll,removeAll等不能保证以原子方式执行因为底层还是调用单次的add等操作,只能保证每一次的操作是原子性的,批量操作需要手动加锁
HashMap -> ConcurrentHashMap
TreeMap -> ConcurrentSkipListMap
key有序,支持更高的并发