天天看點

JUC學習筆記(四)

JUC學習筆記(四)

Vector 是矢量隊列,它是 JDK1.0 版本添加的類。繼承于 AbstractList,實作了 List, RandomAccess, Cloneable 這些接口。 Vector 繼承了 AbstractList,實作了 List;是以,它是一個隊列,支援相關的添加、删除、修改、周遊等功能。 Vector 實作了 RandmoAccess 接口,即提供了随機通路功能。

JUC學習筆記(一)https://www.cnblogs.com/lm66/p/15118407.html JUC學習筆記(二)https://www.cnblogs.com/lm66/p/15118813.html JUC學習筆記(三)https://www.cnblogs.com/lm66/p/15118976.html

NotSafeDemo

異常内容

java.util.ConcurrentModificationException

問題: 為什麼會出現并發修改異常?

檢視 ArrayList 的 add 方法源碼

JUC學習筆記(四)

那麼我們如何去解決 List 類型的線程安全問題?

  Vector 是矢量隊列,它是 JDK1.0 版本添加的類。繼承于 AbstractList,實作了 List, RandomAccess, Cloneable 這些接口。 Vector 繼承了 AbstractList,實作了 List;是以,它是一個隊列,支援相關的添加、删除、修改、周遊等功能。 Vector 實作了 RandmoAccess 接口,即提供了随機通路功能。RandmoAccess 是 java 中用來被 List 實作,為 List 提供快速通路功能的。在

Vector 中,我們即可以通過元素的序号快速擷取元素對象;這就是快速随機通路。 Vector 實作了 Cloneable 接口,即實作 clone()函數。它能被克隆。

和 ArrayList 不同,Vector 中的操作是線程安全的。

NotSafeDemo 代碼修改

現在沒有運作出現并發異常,為什麼?

檢視 Vector 的 add 方法

JUC學習筆記(四)

add 方法被 synchronized 同步修辭,線程安全!是以沒有并發異常

Collections 提供了方法 synchronizedList 保證 list 是同步線程安全的

沒有并發修改異常

檢視方法源碼

JUC學習筆記(四)

首先我們對 CopyOnWriteArrayList 進行學習,其特點如下:

它相當于線程安全的 ArrayList。和 ArrayList 一樣,它是個可變數組;但是和ArrayList 不同的時,它具有以下特性:

它最适合于具有以下特征的應用程式:List 大小通常保持很小,隻讀操作遠多于可變操作,需要在周遊期間防止線程間的沖突。

它是線程安全的。

因為通常需要複制整個基礎數組,是以可變操作(add()、set() 和 remove() 等等)的開銷很大。

疊代器支援 hasNext(), next()等不可變操作,但不支援可變 remove()等操作。

使用疊代器進行周遊的速度很快,并且不會與其他線程發生沖突。在構造疊代器時,疊代器依賴于不變的數組快照。

獨占鎖效率低:采用讀寫分離思想解決

寫線程擷取到鎖,其他寫線程阻塞

複制思想:

  當我們往一個容器添加元素的時候,不直接往目前容器添加,而是先将目前容器進行 Copy,複制出一個新的容器,然後新的容器裡添加元素,添加完元素之後,再将原容器的引用指向新的容器。 這時候會抛出來一個新的問題,也就是資料不一緻的問題。如果寫線程還沒來得及寫會記憶體,其他的線程就會讀到了髒資料。

這就是 CopyOnWriteArrayList 的思想和原理。就是拷貝一份。

沒有線程安全問題

原因分析(重點):動态數組與線程安全

下面從“動态數組”和“線程安全”兩個方面進一步對CopyOnWriteArrayList 的原理進行說明。

“動态數組”機制

它内部有個“volatile 數組”(array)來保持資料。在“添加/修改/删除”資料時,都會建立一個數組,并将更新後的資料拷貝到建立的數組中,最後再将該數組指派給“volatile 數組”, 這就是它叫做 CopyOnWriteArrayList 的原因

由于它在“添加/修改/删除”資料時,都會建立數組,是以涉及到修改資料的操作,CopyOnWriteArrayList 效率很低;但是單單隻是進行周遊查找的話,效率比較高。

“線程安全”機制

通過 volatile 和互斥鎖來實作的。

通過“volatile 數組”來儲存資料的。一個線程讀取 volatile 數組時,總能看到其它線程對該 volatile 變量最後的寫入;就這樣,通過 volatile 提供了“讀取到的資料總是最新的”這個機制的保證。

通過互斥鎖來保護資料。在“添加/修改/删除”資料時,會先“擷取互斥鎖”,再修改完畢之後,先将資料更新到“volatile 數組”中,然後再“釋放互斥鎖”,就達到了保護資料的目的。

線程安全與線程不安全集合

集合類型中存線上程安全與線程不安全的兩種,常見例如:

ArrayList ----- Vector

HashMap -----HashTable

但是以上都是通過 synchronized 關鍵字實作,效率較低

Collections 建構的線程安全集合

ava.util.concurrent 并發包下

CopyOnWriteArrayList CopyOnWriteArraySet 類型,通過動态數組與線程安全個方面保證線程安全