一.List集合
1.1 在多线程同时写的情况下,ArrayList并不是线程安全类,会抛出java.util.ConcurrentModificationException异常,如
private static void notSafeList() {
List<String> list=new ArrayList<>();
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(Thread.currentThread().getName() + "\t" + list);
}, String.valueOf(i)).start();
}
}
解决方法:
使用Vector(ArrayList所有方法加synchronized,太重)
使用Collections.synchronizedList()转换成线程安全类
使用java.concurrent.CopyOnWriteArrayList(推荐)
1.2 CopyOnWriteArrayList是JUC的线程安全类,通过写时复制来实现读写分离。其add()方法,就是先复制一个新数组,长度为原数组长度+1,然后将新数组最后一个元素设为添加的元素
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 不可重复集合
跟List类似,HashSet和TreeSet都不是线程安全的,与之对应的有CopyOnWriteSet这个线程安全类。CopyOnWriteSet这个类底层维护了一个CopyOnWriteArrayList数组
private final CopyOnWriteArrayList<E> al;
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
三、HashSet和HashMap
HashSet底层是用HashMap实现的。既然是用HashMap实现的,那HashMap.put()需要传两个参数,而HashSet.add()只传一个参数,实际上HashSet.add()就是调用的HashMap.put(),只不过Value被写死了,是一个private static final Object对象。
四、Map
HashMap不是线程安全的,Hashtable是线程安全的,但是跟Vector类似,太重量级。所以也有类似CopyOnWriteMap,叫ConcurrentHashMap,其主要使用了分段锁