文章目录
Vector和ArrayList、LinkedList联系和区别?
-
ArrayList: 底层数组实现;实现RandomAccess接口,支持随机访问;在查询时效率高,非顺序添加元素、删除元素效率低;因为需要复制元素;线程不安全。
-
LinkedList:底层双向链表实现;添加、删除元素快;但查询是遍历查询效率低;线程不安全。
-
Vector:底层数组实现,操作的时候使用synchronized进行加锁,线程安全。
使用场景 -
Vector弃用
-
ArrayList:频繁读取集合中的元素时;
-
LinkedList:插入和删除操作较多
如果需要保证线程安全,ArrayList应该怎么做,用有几种方式
使用juc并发包下的工具类
- 使用Collections.synchronizedList(new ArrayList<>()); 原理使用synchronized加锁
- 使用CopyOnWriteArrayList<>() 原理使用ReentrantLock加锁
Collections.synchronizedList()线程安全的原理
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}
根据你传入的List是否实现RandomAccess这个接口来返回的SynchronizedRandomAccessList还是SynchronizedList.
ArrayList实现了 RandomAccess 接口,所以返SynchronizedRandomAccessList对象
那就看看SynchronizedRandomAccessList
static class SynchronizedRandomAccessList<E>
extends SynchronizedList<E>
implements RandomAccess {
SynchronizedRandomAccessList(List<E> list) {
super(list);
}
SynchronizedRandomAccessList(List<E> list, Object mutex) {
super(list, mutex);
}
public List<E> subList(int fromIndex, int toIndex) {
synchronized (mutex) {
return new SynchronizedRandomAccessList<>(
list.subList(fromIndex, toIndex), mutex);
}
}
private static final long serialVersionUID = 1530674583602358482L;
private Object writeReplace() {
return new SynchronizedList<>(list);
}
}
SynchronizedRandomAccessList里面没有什么,但它继承了SynchronizedList
我们看看SynchronizedRandomAccessList继承体系
看看父类SynchronizedList
static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
final List<E> list;
SynchronizedList(List<E> list) {
super(list);
this.list = list;
}
SynchronizedList(List<E> list, Object mutex) {
super(list, mutex);
this.list = list;
}
public boolean equals(Object o) {
if (this == o)
return true;
synchronized (mutex) {return list.equals(o);}
}
public int hashCode() {
synchronized (mutex) {return list.hashCode();}
}
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
public E set(int index, E element) {
synchronized (mutex) {return list.set(index, element);}
}
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
public E remove(int index) {
synchronized (mutex) {return list.remove(index);}
}
public int indexOf(Object o) {
synchronized (mutex) {return list.indexOf(o);}
}
public int lastIndexOf(Object o) {
synchronized (mutex) {return list.lastIndexOf(o);}
}
public boolean addAll(int index, Collection<? extends E> c) {
synchronized (mutex) {return list.addAll(index, c);}
}
public ListIterator<E> listIterator() {
return list.listIterator(); // Must be manually synched by user
}
public ListIterator<E> listIterator(int index) {
return list.listIterator(index); // Must be manually synched by user
}
public List<E> subList(int fromIndex, int toIndex) {
synchronized (mutex) {
return new SynchronizedList<>(list.subList(fromIndex, toIndex),
mutex);
}
}
父类SynchronizedList也是个静态内部类,操作数据都加了synchronized锁,
当我们看SynchronizedList的父类SynchronizedCollection,也能看到SynchronizedCollection类里操作数据也是加了synchronized锁。所以线程安全
CopyOnWriteArrayList<>()线程安全的原理
看看CopyOnWriteArrayList的源码
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 8673264195747942595L;
//ReentrantLock可重入锁
final transient ReentrantLock lock = new ReentrantLock();
//volatile 修饰存放数据的数组
private transient volatile Object[] array;
.......
public boolean add(E e) {
final ReentrantLock lock = this.lock;
//加锁
lock.lock();
try {
//获取当前数组
Object[] elements = getArray();
//获取当前数组长度
int len = elements.length;
// 复制数组到新数组中,并且新数组容量是原来的容量+1
Object[] newElements = Arrays.copyOf(elements, len + 1);
// 元素赋值给新数组
newElements[len] = e;
// 把新数组赋值给当前数组
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
发现CopyOnWriteArrayList操作数据都用了 ReentrantLock加锁。并且通过源码分析,CopyOnWriteArrayList设计思想用了读写分离+最终一致
那么设计也必然也会带来缺点:内存占用问题,写时复制机制,内存里会同时驻扎两个对象的内存,旧的对象和新写入的对象,如果对象大则容易发生Yong GC和Full GC
CopyOnWriteArrayList<>()与 Collections.synchronizedList()的选择
CopyOnWriteArrayList<>() | Collections.synchronizedList() | |
---|---|---|
读 | 效率相对高 | 效率相对低 |
写(增删改) | 效率相对低 | 效率相对高 |
读多选CopyOnWriteArrayList<>(),写多选Collections.synchronizedList()