1、原理
CopyOnWriteArrayList是一個線程安全的ArrayList
如果一段併發程序,讀操作明顯多於寫操作的話,那麼使用CopyOnWriteArrayList的性能會比Vector更高
CopyOnWriteArrayList的實現原理就是讀寫分離,它對所有的寫操作都使用ReentrantLock來加鎖,對所有的讀操作都不加鎖,那它是怎麼保證線程安全性問題的呢?
CopyOnWriteArrayList在寫操作的時候,都會將list中的數組copy一份作爲緩存,然後對該緩存中的數組進行操作(此時若有其他線程過來讀的話,那麼該線程讀的還是原先沒有被修改過的數組,若有其他線程過來寫的話,那麼該線程會因爲ReentrantLock的原因被鎖在外面。),操作完畢後再將list中的數組地址引用指向修改後的新數組地址。
由CopyOnWriteArrayList的原理我們可以看出,我們每次往list裏面寫數據的時候,數組都需要重新copy一份,所以CopyOnWriteArrayList不需要實現像ArrayList一樣的擴容機制,初始創建時讓list中的數組長度爲0,我們每次add元素的時候,只需要對新數組長度進行加1操作即可,所以CopyOnWriteArrayList實現起來相對還是比ArrayList簡單的。
// 構造方法 public CopyOnWriteArrayList() { setArray(new Object[0]); } // 添加一個元素 public boolean add(E e) { // 加鎖 final ReentrantLock lock = this.lock; lock.lock(); try { // 創建一個新數組,長度+1 Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); // 將元素添加到新數組的末端,並將新數組賦值給本對象中的array newElements[len] = e; setArray(newElements); return true; } finally { // 解鎖 lock.unlock(); } } // 獲取一個元素,沒加鎖 public E get(int index) { return get(getArray(), index); }
所以我們可以看出,如果是讀操作十分頻繁的話,那麼多線程下使用CopyOnWriteArrayList的性能基本上跟ArrayList差不多了。但如果是寫操作十分頻繁的話,建議還是不要使用CopyOnWriteArrayList了,因爲它會造成數組的不斷擴容及複製,十分耗性能。這其實就跟我們數據庫讀寫分離的原理是一樣的,如果寫操作很多的話,那麼主從庫就會不斷的執行復制操作,消耗性能。但如果是讀操作多的話,由於該庫只用於讀,所以不會發生數據庫事務鎖,效率就會比一般的單庫查詢快很多。
2、使用
- CopyOnWriteArrayList的使用和ArrayList差不多,這裏沒什麼好說的