使用线程不安全的集合在多线程下会发生异常
java.util.ConcurrentModificationException
例如arraylist hashmap
Arraylist
a.可以使用线程安全的相关集合类
List<String> list = Collections.synchronizedList(new ArrayList<>());
Map<Object, Object> objectObjectMap = Collections.synchronizedMap(new HashMap<>());
b.使用 List<String> list = new CopyOnWriteArrayList<>(); 写时复制
copyonwrit容器即在写时复制的容器。往容器中添加元素的时候,不直接往当前容器中Object[]中添加,而是先将Object[]进行copy
复制出一个新的容器newelements,然后往新的元素中添加元素,添加完元素后在将元素的引用指向新的容器。这样做的好处是可以对容器进行
并发的读操作,而不需要进行加锁,因为当前容器不会添加任何元素。所以copyonwrite容器也是一种读写分离的思想,读和写是不同的容器
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();
}
}
set集合类
new hashset()的底层就是new hashmap() 创建了一个初始为16 负载因子为0.75的hashmap
与arrayList类似,可以使用
a. Collections.synchronizedSet(new HashSet<>());
b. new CopyOnWriteArraySet<>();
map集合类
1. Collections.synchronizedMap(new HashMap<>());
2. new ConcurrentHashMap<>();
jdk1.7
ConcurrentHashMap 采用了分段锁技术,其中 Segment 继承于 ReentrantLock。
不会像 HashTable 那样不管是 put 还是 get 操作都需要做同步处理,理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发。每当一个线程占用锁访问一个 Segment 时,不会影响到其他的 Segment。
jdk1.8
其中抛弃了原有的 Segment 分段锁,而采用了 CAS + synchronized 来保证并发安全性。