一、线程不安全的List
ArrayList
特点:
- 有点:查询和更新元素值比较快。
- 缺点:添加或删除一个元素需要移动数组中的其它元素。
容量:
- 初始容量:0
- 扩容:
- 调用add方法时,若ArrayList中元素的数量(size)等于等于对象数组(elementData)的长度时会触发扩容操作,容量第一次扩展为10,之后每次扩展为之前的1.5倍。调用remove方法,不会进行缩容操作。
- 代码:
- 扩容1.5倍: newCapacity = oldCapacity + (oldCapacity >> 1);
- 扩容时对数组进行复制:elementData = Arrays.copyOf(elementData, newCapacity);
- 说明:
- 虽然ArrayList类的初始容量默认为10(private static final int DEFAULT_CAPACITY = 10;)
- 但实际上在new ArrayList()后,ArrayList的elementData(transient Object[] elementData;)的length为0
- 在第一次调用add方法时,elementData的length才初始化为10。
LinkedList
二、线程安全的List
Collections.synchronizedList(List list)
举例:
- List<String> syncArraylist = Collections.synchronizedList(new ArrayList<String>());
- List<String> syncLinkedList = Collections.synchronizedList(new LinkedList<String>());
说明:
- Collections.synchronizedList(List list)实际上是创建了一个java.util.Collections的内部类SynchronizedList。
- SynchronizedList只是在自己的方法中使用同步代码块将List(封装的ArrayList、linkedList等)里相应的方法包裹了起来,故SynchronizedList的扩容方式同它封装的list一样。
- SynchronizedList还可以指定锁对象,如不指定,默认为this。
CopyOnWriteArrayList:
- 使用ReentrantLock来实现线程的同步。
- 每添加一个元素,就进行一次数组的copy,故CopyOnWriteArrayList的写性能非常的糟糕。
- 多线程环境下,CopyOnWriteArrayList的读性能比Collections.SynchronizedList的读性能好一些(后者的get方法也被同步代码块包裹了,故读性能稍差一点)。
Vector
线程安全:
- Vector是线程安全的(方法是Synchronized的)
容量:
- 初始容量:10
扩容:
- 每次扩展为之前的2倍。
- 代码:
- 扩容2倍: int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); // capacityIncrement默认为0
- 扩容时对数组进行复制: elementData = Arrays.copyOf(elementData, newCapacity);
三、ArrayList VS Vector
不同点:
- ArrayList非线程安全,Vector线程安全。
- ArrayList扩容后容量变为之前的1.5倍,Vector扩容后容量是之前的2倍,故ArrayList更省空间。
相同点:
- 都是基于Object数组实现的。
- 都允许添加null元素。
四、ArrayList VS LinkedList
不同点:
- 对于随机访问get和set,ArrayList比LinkedList快。
- 对于插入和删除操作,LinkedList比较快。
相同点:
- 都允许添加null元素。
结论:
- 从时间复杂度来说:如果对list增加或删除操作较多,则建议使用LinkedList;如果对list查询操作较多,则建议使用ArrayList。
- 从空间复杂度来说:LinkedList占用的空间较多(链表中的每一个节点都需要两个引用来指向它的previous节点和next节点)。