List
集合类我们平时最常用的就是ArrayList<>,单线程情况下,性能较高。
但是碰到多线程的时候就很容易炸,因为它是线程不安全的!
为何不安全?因为它的add()方法没有锁!
public boolean add(E e) {
add(size(), e);
return true;
}
所以在多线程并发的情况下就可能出现ConcurrentModificationException并发修改异常!
怎么解决呢?
1.vector
既然这个ArrayList是线程不安全的集合,我们直接用vector这种线程安全的集合不就行了?
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
行是行,但vector是jdk1.0版本就出了,而ArrayList却在后面的1.2版本才出?为何多此一举呢?
主要是因为vector的效率太低了!别急,还有其他方法!
2.集合工具类Collections.synchronizedList(list)
集合工具类Collections就提供了帮你锁住的list方法,你就可以把arrayList丢进去加个锁!
List list= Collections.synchronizedList(new ArrayList<>());
3.JUC工具类concurrent包中的C opyOnWirteArrayList()
提供了一个写时读的集合,可以说是读写分离,其他线程在读取内存中的数据时并不会被影响。
import java.util.concurrent.CopyOnWriteArrayList;
---
List list = new CopyOnWriteArrayList();
将目标集合拷贝出来后,用lock锁住,扩容一个长度,将新值丢到新扩容的下标后,再将这个集合替换掉原来的数组,之后释放锁
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
set之所以不会有重复的元素,如HashSet就是因为它的底层其实是包装了一个HashMap。
每次将值放进key中,value则固定放了一个名为present的Object常量。
这也是为什么set在add时只需一个参数,而map需要两个参数的解决方法!
那么Set不安全怎么解决?一样的套路,一样的技巧,跟list都是collection的子类,举一反三!
1.集合工具类Collections.synchronizedSet(HaspSet)
Set<Object> set = Collections.synchronizedSet(new HashSet<>());
同样的这个集合工具类也提供了一个方法直接锁住!
2.JUC 工具类CopyOnWriteArraySet()
CopyOnWriteArraySet set= new CopyOnWriteArraySet<>();
其实底层就是套了一个上面的CopyOnWriteArrayList对象!
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
Map
虽然Collections也提供了一个synchronizedMap(),但在原子性上显然不够完美,HashMap就直接使用ConcurrentHashMap()即可!
ConcurrentHashMap map = new ConcurrentHashMap();