java中線程安全和非線程安全的集合


 

線程安全

非線程安全

Collection

Vector

ArrayList、LinkedList

 

HashSet、TreeSet

Map

HashTable

HashMap、TreeMap

字符串

StringBuffer

StringBuilder

一、ArrayList和vector區別
Vector和ArrayList間唯一的區別就是Vector每個方法都自帶同步機制。
例:比如我要往集合里面加一個元素,又要保證多個線程不會同時調用同一個對象的add()方法,ArrayList里面就要這樣寫:

ArrayList<String> list = new ArrayList<>();
synchronized (list) {
    list.add("233");
}

而Vector里面只要這樣寫就行了:

Vector<String> list = new Vector<>();
list.add("233");

因為ArrayList的add方法是這樣定義的:

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

而Vector的add方法是這樣定義的:

    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

二、HashTable、HashMap、HashSet:
HashTable和HashMap采用的存儲機制是一樣的,不同的是:
1、HashMap:
a. 非線程安全;
b. 采用數組方式存儲key-value構成的Entry對象,key允許為null,無容量限制;
c. 遍歷使用的是Iterator迭代器;

2、HashTable:
a. 線程安全; (對方法加上synchronized
b. 無論是key還是value都不允許有null值的存在;在HashTable中調用Put方法時,如果key為null,直接拋出NullPointerException異常;
c. 遍歷使用的是Enumeration列舉;

3、HashSet:
a. 非線程安全
b. 底層通過HashMap實現,無容量限制;
c. 不保證數據的有序;

在HashSet中,元素都存到HashMap鍵值對的Key上面,而Value是統一的值private static final Object PRESENT = new Object();,(定義一個虛擬的Object對象作為HashMap的value,將此對象定義為static final。)
HashSet的add(E e)底層實現調用hashmap的put(E e),將該元素作為key放入HashMap。
由於HashMap的put()方法添加key-value對時,當新放入HashMap的Entry中key與集合中原有Entry的key相同(hashCode()返回值相等,通過equals比較也返回true), 新添加的Entry的value會將覆蓋原來Entry的value,但key不會有任何改變, 因此如果向HashSet中添加一個已經存在的元素時,新添加的集合元素將不會被放入HashMap中, 原來的元素也不會有任何改變,這也就滿足了Set中元素不重復的特性。

HashSet參考:http://zhangshixi.iteye.com/blog/673143

三、TreeSet、TreeMap:
TreeSet和TreeMap都是完全基於Map來實現的,並且都不支持get(index)來獲取指定位置的元素,需要遍歷來獲取。另外,TreeSet還提供了一些排序方面的支持,例如傳入Comparator實現、descendingSet以及descendingIterator等。
1、TreeSet:
a. 非線程安全
b. 底層基於TreeMap實現,支持排序;

2、TreeMap:
a. 非線程安全;
b. 典型的基於紅黑樹的Map實現,因此它要求一定要有key比較的方法,要么傳入Comparator比較器實現,要么key對象實現Comparator接口;

與hashmap相比,treemap內部的元素都是排序的,當需要查找某些元素以及順序輸出元素的時候占優勢。因此,TreeMap是一個內部元素排序版的HashMap

四、StringBuffer和StringBulider:
StringBuilder與StringBuffer都繼承自AbstractStringBuilder類,在AbstractStringBuilder中也是使用字符數組保存字符串。
它們是字符串變量,是可改變的對象,每當我們用它們對字符串做操作時,實際上是在一個對象上操作的,不像String一樣創建一些對象進行操作,所以速度就快了;
1、在執行速度方面的比較:StringBuilder > StringBuffer ;
2、StringBuilder:非線程安全;
3、StringBuffer:線程安全; (對方法加上synchronized
 
對於String、StringBuffer和StringBulider三者使用的總結:
1.如果要操作少量的數據:String
2.單線程操作字符串緩沖區下操作大量數據:StringBuilder
3.多線程操作字符串緩沖區下操作大量數據:StringBuffer


非線程安全!=不安全
雖然ArrayList是線程不安全的,但不代表在多線程下不能使用ArrayList,只能使用Vector。
非線程安全並不是多線程環境下就不能使用。線程安全問題在於:多線程操作同一個對象。注意是同一個對象。比如最上面那個模擬,就是在主線程中new的一個ArrayList然后多個線程操作同一個ArrayList對象。
如果是每個線程中new一個ArrayList,而這個ArrayList只在這一個線程中使用,那么肯定是沒問題的。

參考:
https://blog.csdn.net/u011389474/article/details/54602812
https://www.zhihu.com/question/49855966


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM