Java中各種集合(字符串類)的線程安全性!!!
一、概念:
- 線程安全:就是當多線程訪問時,采用了加鎖的機制;即當一個線程訪問該類的某個數據時,會對這個數據進行保護,其他線程不能對其訪問,直到該線程讀取完之后,其他線程才可以使用。防止出現數據不一致或者數據被污染的情況。
- 線程不安全:就是不提供數據訪問時的數據保護,多個線程能夠同時操作某個數據,從而出現數據不一致或者數據污染的情況。
- 對於線程不安全的問題,一般會使用synchronized關鍵字加鎖同步控制。
- 線程安全 工作原理: jvm中有一個main memory對象,每一個線程也有自己的working memory,一個線程對於一個變量variable進行操作的時候, 都需要在自己的working memory里創建一個copy,操作完之后再寫入main memory。
當多個線程操作同一個變量variable,就可能出現不可預知的結果。
而用synchronized的關鍵是建立一個監控monitor,這個monitor可以是要修改的變量,也可以是其他自己認為合適的對象(方法),然后通過給這個monitor加鎖來實現線程安全,每個線程在獲得這個鎖之后,要執行完加載load到working memory 到 use && 指派assign 到 存儲store 再到 main memory的過程。才會釋放它得到的鎖。這樣就實現了所謂的線程安全。
二、線程安全(Thread-safe)的集合對象:
- Vector
- HashTable
- StringBuffer
三、非線程安全的集合對象:
- ArrayList :
- LinkedList:
- HashMap:
- HashSet:
- TreeMap:
- TreeSet:
- StringBulider:
四、相關集合對象比較:
- Vector、ArrayList、LinkedList:
1、Vector:
Vector與ArrayList一樣,也是通過數組實現的,不同的是它支持線程的同步,即某一時刻只有一個線程能夠寫Vector,避免多線程同時寫而引起的不一致性,但實現同步需要很高的花費,因此,訪問它比訪問ArrayList慢。
2、ArrayList:
a. 當操作是在一列數據的后面添加數據而不是在前面或者中間,並需要隨機地訪問其中的元素時,使用ArrayList性能比較好。
b. ArrayList是最常用的List實現類,內部是通過數組實現的,它允許對元素進行快速隨機訪問。數組的缺點是每個元素之間不能有間隔,當數組大小不滿足時需要增加存儲能力,就要講已經有數組的數據復制到新的存儲空間中。當從ArrayList的中間位置插入或者刪除元素時,需要對數組進行復制、移動、代價比較高。因此,它適合隨機查找和遍歷,不適合插入和刪除。
3、LinkedList:
a. 當對一列數據的前面或者中間執行添加或者刪除操作時,並且按照順序訪問其中的元素時,要使用LinkedList。
b. LinkedList是用鏈表結構存儲數據的,很適合數據的動態插入和刪除,隨機訪問和遍歷速度比較慢。另外,他還提供了List接口中沒有定義的方法,專門用於操作表頭和表尾元素,可以當作堆棧、隊列和雙向隊列使用。
Vector和ArrayList在使用上非常相似,都可以用來表示一組數量可變的對象應用的集合,並且可以隨機的訪問其中的元素。
-
HashTable、HashMap、HashSet:
HashTable和HashMap采用的存儲機制是一樣的,不同的是:
1、HashMap:
a. 采用數組方式存儲key-value構成的Entry對象,無容量限制;
b. 基於key hash查找Entry對象存放到數組的位置,對於hash沖突采用鏈表的方式去解決;
c. 在插入元素時,可能會擴大數組的容量,在擴大容量時須要重新計算hash,並復制對象到新的數組中;
d. 是非線程安全的;
e. 遍歷使用的是Iterator迭代器;2、HashTable:
a. 是線程安全的;
b. 無論是key還是value都不允許有null值的存在;在HashTable中調用Put方法時,如果key為null,直接拋出NullPointerException異常;
c. 遍歷使用的是Enumeration列舉;3、HashSet:
a. 基於HashMap實現,無容量限制;
b. 是非線程安全的;
c. 不保證數據的有序;
-
TreeSet、TreeMap:
TreeSet和TreeMap都是完全基於Map來實現的,並且都不支持get(index)來獲取指定位置的元素,需要遍歷來獲取。另外,TreeSet還提供了一些排序方面的支持,例如傳入Comparator實現、descendingSet以及descendingIterator等。
1、TreeSet:
a. 基於TreeMap實現的,支持排序;
b. 是非線程安全的;2、TreeMap:
a. 典型的基於紅黑樹的Map實現,因此它要求一定要有key比較的方法,要么傳入Comparator比較器實現,要么key對象實現Comparator接口;
b. 是非線程安全的;
-
StringBuffer和StringBulider:
StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數組保存字符串。
1、在執行速度方面的比較:StringBuilder > StringBuffer ;
2、他們都是字符串變量,是可改變的對象,每當我們用它們對字符串做操作時,實際上是在一個對象上操作的,不像String一樣創建一些對象進行操作,所以速度快;
3、 StringBuilder:線程非安全的;
4、StringBuffer:線程安全的;
對於String、StringBuffer和StringBulider三者使用的總結:
1.如果要操作少量的數據用 = String
2.單線程操作字符串緩沖區 下操作大量數據 = StringBuilder
3.多線程操作字符串緩沖區 下操作大量數據 = StringBuffer
