文章目錄
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()