copyonwritearraylist是乙個執行緒安全的arraylist,對其進行的修改操作都是在底層的乙個複製的陣列(快照)上進行的,也就是使用了寫時複製策略。如圖所示是copyonwritearraylist的類圖結構:
上圖有個小瑕疵,lock 是 包級私有,而不是 protected。
能夠看到,每個copyonwritearraylist物件都有乙個array陣列用來存放具體元素,而reentrantlock則用來保證只有乙個執行緒對array進行修改。reentrantlock本身是乙個獨佔鎖,同時只有乙個執行緒能夠獲取。接下來看一下其中的一些方法**。
共有三個建構函式:
public
copyonwritearraylist()
public
copyonwritearraylist
(e tocopyin)
//將傳入引數集合中的元素複製到本list中
public
copyonwritearraylist
(collection<
?extends
e> c)
setarray
(elements)
;}
setarray方法很簡單:
final
void
setarray
(object[
] a)
新增元素有很多方法,包括add(e e), add(int index, e element)等,原理基本上相同,所以我們只看add(e e)的原始碼。
public
boolean
add(e e)
finally
}
**很簡單,就是將原來的元素複製到了乙個新陣列中,且長度應該加1,然後在新陣列末尾加上要新增的元素,最後設定新陣列為自己的array。
使用e get(int index)方法獲取下標為index的元素:
public e get
(int index)
final object[
]getarray()
private e get
(object[
] a,
int index)
這個方法是執行緒不安全的,因為這個分成了兩步,分別是獲取陣列和獲取元素,而且中間過程沒有加鎖。假設當前執行緒在獲取陣列(執行getarray())後,其他執行緒修改了這個copyonwritearraylist,那麼它裡面的元素就會改變,但此時當前執行緒返回的仍然是舊的陣列,所以返回的元素就不是最新的了,這就是寫時複製策略產生的弱一致性問題。
使用e set (int index, e element)修改list中指定元素的值,**如下:
public e set
(int index, e element)
else
return oldvalue;
}finally
}
使用public e remove(int index)方法,**如下:
public e remove
(int index)
return oldvalue;
}finally
}
也很簡單,就是將元素分兩次複製到新陣列中,然後設定array為新陣列。返回的是刪除的元素。
我們先看一下迭代器是怎麼使用的:
public
static
void
main
(string[
] args)
很簡單,那弱一致性是怎麼回事呢,它是指返回迭代器後,其他執行緒對list的增刪改對迭代器是不可見的。接下來看一下為什麼會這樣:
public iterator
iterator()
static
final
class
cowiterator
implements
listiterator
public
boolean
hasnext()
@suppresswarnings
("unchecked"
)public e next()
在呼叫iterator()方法後,會返回乙個cowiterator物件,cowiterator物件的snapshot變數儲存了當前list的內容,cursor是遍歷list時資料的下標。
那麼為什麼說snapshot是list的快找呢,明明傳的是引用。其實這就和copyonwritearraylist本身有關了,如果在返回迭代器後沒有對裡面的陣列array進行修改,則這兩個變數指向的確實是同乙個陣列;但是若修改了,則根據前面所講,它是會新建乙個陣列,然後將修改後的陣列複製到新建的陣列,而老的陣列就會被「丟棄」,所以如果修改了陣列,則此時snapshot指向的還是原來的陣列,而array變數已經指向了新的修改後的陣列了。這也就說明獲取迭代器後,使用迭代器元素時,其他執行緒對該list的增刪改不可見,因為他們操作的是兩個不同的陣列,這就是弱一致性。
接下來就演示一下這個現象:
public
class
copylist})
; iterator
itr = arraylist.
iterator()
; threadone.
start()
; threadone.
join()
;while
(itr.
hasnext()
) system.out.
println
(itr.
next()
);}}
執行結果如下,說明雖然執行緒threadone改變了這個list,但是獲取了迭代器後,它指向的還是舊的陣列,所以遍歷的時候還是舊的陣列內容。所以==獲取迭代器的操作必須在子執行緒操作之前進行。
hello
alibaba
welcome
tohangzhou
copyonwritearraylist使用寫時複製策略保證list的一致性,而獲取–修改–寫入三個步驟不是原子性,所以需要乙個獨佔鎖保證修改資料時只有乙個執行緒能夠進行。另外,copyonwritearraylist提供了弱一致性的迭代器,從而保證在獲取迭代器後,其他執行緒對list的修改是不可見的,迭代器遍歷的陣列是乙個快照。 CopyOnWriteArrayList原始碼解讀
概述copyonwritearraylist是jdk concurrent包中提供的乙個非阻塞型的,執行緒安全的list實現。copyonwritearraylist在進行資料修改時,都不會對資料進行鎖定,每次修改時,先拷貝整個陣列,然後修改其中的一些元素,完成上述操作後,替換整個陣列的指標。對co...
CopyOnWriteArrayList 原始碼分析
1.copyonwritearraylist 是執行緒安全的arraylist,適用於儲存的資料量不大,讀操作遠多於寫操作,對實時性要求不高的場景。copyonwritearraylist 對 讀操作不同步,對寫操作同步。在進行寫操作時,會對共享變數進行copy,在副本上進行更新,然後將更新好的副本...
CopyOnWriteArrayList原始碼分析
原始碼基於1.8.0 112 copyonwritearraylist也是通過陣列來儲存元素,閱讀過之前的arraylist的話這邊應該很容易理解 原理 copyonwritearraylist內部通過陣列來儲存資料,每次修改list都會產生乙個新的陣列,然後複製原始資料。修改方法都通過內部的而乙個...