ArrayList是大家用的再熟悉不过的集合了,而此集合设计之初也是为了高效率,并未考虑多线程场景下,所以也就有了多线程下的CopyOnWriteArrayList这一集合
回忆下ArrayList
fail-fast快速失败机制,一个线程A在用迭代器遍历集合时,另个线程B这时对集合修改会导致A快速失败,抛出ConcurrentModificationException 异常。在java.util中的集合类都是快速失败的
fail-safe安全失败机制,遍历时不在原集合上,而是先复制一个集合,在拷贝的集合上进行遍历。在java.util.concurrent包下的容器类是安全失败的,建议在并发环境下使用这个包下的集合类
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable { }
ArrayList是实现List接口的可变数组,并允许null在内的重复元素
底层数组实现,扩容时将老数组元素拷贝到新数组中,每次扩容是其容量的1.5倍,操作代价高
采用了Fail-Fast机制,面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险
ArrayList是线程不安全的,所以在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList
ArrayList默认大小(为什么是这个?),扩容机制?
ArrayList特点访问速度块,为什么?插入删除一定慢吗?适合做队列吗?
ArrayList 底层实现就是数组,访问速度本身就很快,为何还要实现 RandomAccess ?
优缺点
ArrayList中的Fail-fast机制
Vector真的安全吗
public class CaptainTest {
private static Vector<Integer> vector = new Vector();
public static void main(String[] args) {
while (true) {
for (int i = 0; i < 10; i++) {
vector.add(i); //往vector中添加元素
}
Thread removeThread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < vector.size(); i++) {
Thread.yield();
//移除第i个数据
vector.remove(i);
}
}
});
Thread printThread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < vector.size(); i++) {
Thread.yield();
//获取第i个数据并打印
System.out.println(vector.get(i));
}
}
});
removeThread.start();
printThread.start();
//避免同时产生过多线程
while (Thread.activeCount() > 20) ;
}
}
}
CopyOnWriteArrayList
public static void main(String[] args) {
CopyOnWriteArrayList list = new CopyOnWriteArrayList();
list.add("test1");
Thread addThread = new Thread(new Runnable() {
@Override
public void run() {
list.add("test4");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
addThread.start();
}
remove和iterator
CopyOnWriteArrayList优缺点分析
有道无术,术可成;有术无道,止于术
欢迎大家关注Java之道公众号
好文章,我在看❤️