Collections.synchronizedList(new ArrayList())
來使ArrayList變成是線程安全的話,也是幾乎都是每一個方法都加上synchronized關鍵字的,只不過它不是加在方法的聲明處,而是方法的內部。多線程下for循環迭代Vector或者SynchronizedList,進行delete和get操做會發生數組下標錯誤的異常。java
for-each
(迭代器)來遍歷咱們的集合,好處就是簡潔、數組索引的邊界值只計算一次。for-each
(迭代器)來作上面的操做,會拋出ConcurrentModificationException異常。若是想要完美解決上面所講的問題,咱們能夠在遍歷前加鎖:數組
- Hashtable、Vector加鎖的粒度大(直接在方法聲明處使用synchronized)
- ConcurrentHashMap、CopyOnWriteArrayList加鎖粒度小(用各類的方式來實現線程安全,好比咱們知道的ConcurrentHashMap用了cas鎖、volatile等方式來實現線程安全..)
- JUC下的線程安全容器在遍歷的時候不會拋出ConcurrentModificationException異常
- CopyOnWriteArrayList是線程安全容器(相對於ArrayList),底層經過複製數組的方式來實現。
- CopyOnWriteArrayList在遍歷的使用不會拋出ConcurrentModificationException異常,而且遍歷的時候就不用額外加鎖
- 元素能夠爲null
/** 可重入鎖對象 */ final transient ReentrantLock lock = new ReentrantLock(); /** CopyOnWriteArrayList底層由數組實現,volatile修飾 */ private transient volatile Object[] array; final Object[] getArray() { return array; } final void setArray(Object[] a) { array = a; } // 初始化CopyOnWriteArrayList至關於初始化數組 public CopyOnWriteArrayList() { setArray(new Object[0]); }
CopyOnWriteArrayList底層就是數組,加鎖就交由ReentrantLock來完成。安全
內存佔用:若是CopyOnWriteArrayList常常要增刪改裏面的數據,常常要執行add()、set()、remove()
的話,那是比較耗費內存的。多線程
add()、set()、remove()
這些增刪改操做都要複製一個數組出來。數據一致性:CopyOnWrite容器只能保證數據的最終一致性,不能保證數據的實時一致性。線程
setArray()
了)。可是線程A迭代出來的是原有的數據。