ArrayList是非線程安全的,在多線程的情況下,向list插入數據的時候,可能會造成數據丟失的情況.並且一個線程在遍歷List,另一個線程修改List,會報ConcurrentModificationException(並發修改異常)錯誤.
解決的方案有兩種:Vector 或 Collections.synchronizedList(List list).
Vector
Vector是一個線程安全的List,但是它的線程安全實現方式是對所有操作都加上了synchronized關鍵字,這種方式嚴重影響效率.所以並不推薦使用Vector.
Collections.synchronizedList(List list)
Collections.synchronizedList
使用方法:
List<String> list = Collections.synchronizedList(new ArrayList<String>()); list.add("1"); list.add("2"); list.add("3"); synchronized (list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) { //foo(i.next()); System.out.println(i.next()); } }
為什么使用時在調用add()方法時不需要再加synchronized修飾,而遍歷的時候需要加synchronized?
首先來看下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.
下面再看一下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); } } @Override public void replaceAll(UnaryOperator<E> operator) { synchronized (mutex) {list.replaceAll(operator);} } @Override public void sort(Comparator<? super E> c) { synchronized (mutex) {list.sort(c);} } ... ... }
可以看出執行add()等方法的時候是加了synchronized關鍵字的,但是listIterator(),iterator()卻沒有加.所以在使用的時候需要加上synchronized.