微信公衆號:放開我我還能學分享知識,共同進步!java
ArrayList 有什麼缺點?
你用過線程安全的集合嗎?
有,說在哪使用。數組
沒有,不過我瞭解過。安全
那你說說它們的實現。
Vector微信
Vector 自己比較低效,由於它的實現基本就是將 add、get、set 等各類方法加上 synchronized 鎖。這就致使了全部併發操做都要競爭同一把鎖,一個線程在進行同步操做時,其餘線程只能等待,大大下降了併發操做的效率。併發
Collections#SynchronizedList高併發
同步包裝器 SynchronizedList 雖然沒使用方法級別的 synchronized 鎖,可是使用了同步代碼塊的形式,本質上仍是沒有改進。spa
CopyOnWriteArrayList線程
CopyOnWriteArrayList 是一個寫時複製的容器,當咱們往一個容器添加元素的時候,不直接往當前容器添加,而是先將當前容器進行 Copy,複製出一個新的容器,而後往新的容器裏添加元素,添加完元素以後,再將原容器的引用指向新的容器。這樣作的好處是咱們能夠對 CopyOnWriteArrayList 進行併發的讀,而不須要加鎖,由於當前容器不會添加任何元素。因此 CopyOnWriteArrayList 是一種讀寫分離的容器,適用於讀多寫少的場景,支持高併發讀取。code
CopyOnWriteArrayList 是如何保證寫時線程安全的?
使用了 ReentrantLock 獨佔鎖,保證同時只有一個線程對集合進行修改操做。對象
如何理解 CopyOnWrite 思想?
寫時複製。就是在寫的時候,拷貝一份原對象,只操做拷貝的對象,操做完後再覆蓋原對象,保證 volatile 語義。
CopyOnWriteArrayList 的缺點是什麼?
CopyOnWriteArrayList 在使用迭代器時是否有什麼注意事項?
咱們知道,CopyOnWriteArrayList 是底層使用一種安全失敗機制。也就是說,能夠在迭代時進行增刪改操做。
不過,在迭代器使用時有一個注意事項:迭代器獲取的數據取決於迭代器建立的時候,而不是迭代器迭代的時候。
請看下面示例:
public static void main(String[] args) { CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>(new Integer[]{1, 2, 3}); ListIterator<Integer> iterator1 = list.listIterator(); list.add(4); ListIterator<Integer> iterator2 = list.listIterator(); iterator1.forEachRemaining(System.out::print); // 123 System.out.println(); iterator2.forEachRemaining(System.out::print); // 1234 }
從上能夠看出,iterator1 在添加數據 4 以前就之前建立,那麼最終它遍歷獲取的數據是 123,而 iterator2 在添加完數據 4 以後才建立,那麼最終它遍歷獲取的數據是 1234。
下面我說下緣由。
無論是調用 iterator 方法獲取迭代器,仍是調用 listIterator 方法獲取迭代器,內部都會返回一個 COWIterator 對象。
進入 COWIterator 構造方法查看,發如今構造方法中會把 array 數組賦值給 snapshot 變量,若是其餘線程沒有對 CopyOnWriteArrayList 進行增刪改的操做,那麼 snapshot 就是自己的 array,可是若是其餘線程對 CopyOnWriteArrayList 進行了增刪改的操做,那麼舊的數組會被新的數組給替換掉,可是 snapshot 仍是原來舊的數組的引用。也就是說,當咱們使用迭代器遍歷獲取數據時,不能保證拿到的數據是最新的。
獲取更多最新文章,關注公衆號【放開我我還能學】