1. ArrayList的线程安全问题:
public static void main(String[] args) {
final List<Integer> list = new ArrayList<Integer>();
for (int i=0;i<5000;i++) {
list.add(i);
}
//开始5个线程,每个线程添加1000个数据
for(int i=0;i<5;i++) {
new Thread(new Runnable() {
@Override
public void run() {
for(int j=0;j<1000;j++){
list.add(j);
}
}
}).start();
}
//开启5个线程,每个线程删除1000个数据
for (int i=0;i<5;i++){
new Thread(new Runnable() {
@Override
public void run() {
for(int j=0;j<1000;j++){
list.remove(0);
}
}
}).start();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {}
System.out.printf("list size="+list.size());
}
运行发现结果不是5000,每次运行的结果可能都不一样,如果换成vector呢结果就会得到想要的5000,换成CopyOnWriteArrayList也可以得到想要结果,既然Vector和CopyOnWriteArrayList都是线程安全的,那他两有什么不同呢
2. Vector的实现:
a. vector的方法是synchronized的,也就是线程安全的,这也会导致其性能比ArrayList低
b. Vector扩容比ArrayList大,每次扩容为1倍而ArrayList为0.5倍,这就说明当初始化容量不足时,ArrayList更节省空间,源码如下:
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
private void ensureCapacityHelper(int minCapacity) {
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object[] oldData = elementData;
int newCapacity = (capacityIncrement > 0) ?
(oldCapacity + capacityIncrement) : (oldCapacity * 2);
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
c. Vector和ArrayList一样不支持读写并发操作,否则会抛出并发异常ConcurrentModificationException,这个需要注意的
3. CopyOnWriteArrayList的实现:
a. 使用ReentrantLock锁保证线程安全,CopyOnWriteArrayList新增时会新建一个数组添加,添加完成后再将原数组指向新的数组,这就导致内存占用问题,如果对象比较大可能会导致频繁发生Yong GC和Full GC,使用时需要注意内存问题
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(); } } final void setArray(Object[] a) { array = a; }
b. CopyOnWriteArrayList的这种读写分离机制没有锁定原数组,也就是可以同时读取原数组数据,不过读取的是修改前的旧数据,达到了读写并发要求
public E get(int index) { return (E)(getArray()[index]); } final Object[] getArray() { return array; }
c . CopyOnWriteArrayList能保证数据的最终一致性,但不能保证数据的实时一致性,这个需注意
4. 总结
a. ArrayList是线程不安全的
b. Vector线程安全,但性能低
c. CopyOnWriteArrayList线程安全,性能高同时支持并发操作