ArrayList部分源码
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
/**
* 列表元素集合数组
* 如果新建ArrayList对象时没有指定大小,那么会将EMPTY_ELEMENTDATA赋值给elementData,
* 并在第一次添加元素时,将列表容量设置为DEFAULT_CAPACITY
*/
transient Object[] elementData;
/**
* 列表大小,elementData中存储的元素个数
*/
private int size;
}
add方法
public boolean add(E e) {
/**
* 添加一个元素时,做了如下两步操作
* 1.判断列表的capacity容量是否足够,是否需要扩容
* 2.真正将元素放在列表的元素数组里面
*/
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ArrayList线程不安全的表现
在多个线程进行add操作时可能会导致elementData数组越界。
public static void main(String[] args) throws InterruptedException {
final List<Integer> list = new ArrayList<Integer>();
// 线程A将0-1000添加到list
new Thread(() -> {
for (int i = 0; i < 1000 ; i++) {
list.add(i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
// 线程B将1000-2000添加到列表
new Thread(() -> {
for (int i = 1000; i < 2000 ; i++) {
list.add(i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Thread.sleep(1000);
// 打印所有结果
for (int i = 0; i < list.size(); i++) {
System.out.println("第" + (i + 1) + "个元素为:" + list.get(i));
}
}
多线程情况下,一个线程正在写入,另一个线程也在写入,导致数据不一致异常,并发生修改异常 java.util.ConcurrentModificationException
public static void main(String[] args) throws InterruptedException {
List<String> list = new ArrayList<>();
for (int i =1; i<=30 ; i++) {
new Thread(() -> {
list.add("a");
list.add("b");
list.add("c");
list.add("d");
System.out.println(list.toString());
}).start();
}
}
解决办法
//Synchronized对代码进行加锁,力度大,所以代码执行效率低下
List<String> list = Collections.synchronizedList(new ArrayList<String>());
//写时复制通过lock机制进行枷锁
/*CopyOnWrite容器即写时复制的容器。往一个容器添加元索的时候,不直接往当前容器Object[]添加,
而是先将当前容器Object[]进行Copy,复制出一个新的容器object[] newElements,
然后往新的容器object[] newElements 里添加元素,
添加完元素之后,再将原容器的引用指向新的容器setArray(newElements);。
这样做的好处是可以CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。
所以CopyOnWrite 容器也是一种读写分离的思想,读和写不同的容器*/
List<String> list = new CopyOnWriteArrayList();
List<String> list = new Vector<>();
CopyOnWriteArrayList add方法源码
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
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();
}
}
额外说下 ArrayList与LinkedList;这两个都是接口List下的一个实现,用法都一样,但用的场所的有点不同,ArrayList适合于进行大量的随机访问的情况下使用,LinkedList适合在表中进行插入、删除时使用,二者都是非线程安全,解决方法同上(为了避免线程安全,以上采取的方法,特别是第二种,其实是非常损耗性能的)
————————————————
网友评论