新聞中心
同步容器
在之前講Java基礎的時候給大家講過集合容器框架,比如Arraylist,LinkedLsit這些熟知的,它們都不是線程安全的。在多線程環(huán)境中,去訪問這些容器就會出現(xiàn)并發(fā)安全問題。

讓客戶滿意是我們工作的目標,不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領域值得信任、有價值的長期合作伙伴,公司提供的服務項目有:域名申請、雅安服務器托管、營銷軟件、網(wǎng)站建設、敖漢網(wǎng)站維護、網(wǎng)站推廣。
那什么是同步容器,可以先簡單的理解通過使用鎖來實現(xiàn)同步的容器,主要的同步容器類有:
- Vector
- Stack
- HashTable
- Collections.synchronizedXXX(組成的方法)
這里給大家介紹一下Vector,很簡單,它也是實現(xiàn)了List接口,我們看下它的add() 和 get()方法
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}Vector和Hashtable是線程安全的容器類,實現(xiàn)同步的方式是通過對方法加鎖(sychronized)方式實現(xiàn)的,這樣讀寫均需要鎖操作,導致性能低下。
而即使是Vector這樣線程安全的類,在面對多線程下的復合操作的時候也是需要通過客戶端加鎖的方式保證原子性
并發(fā)容器
上面我們聊到到同步容器有一些性能的缺點,針對不同的場景,為了提高容器的并發(fā)訪問,所以我們往往會使用并發(fā)容器。
例如上節(jié)給大家講的BlockingQueue其實它也是并發(fā)容器的一種,例如CopyOnWrite容器,這里不給大家過多介紹,可以自行查閱。我們重點要說的是并發(fā)Map
ConcurrentMap接口
public interface ConcurrentMapextends Map {
//插入元素
V putIfAbsent(K key, V value);
//移除元素
boolean remove(Object key, Object value);
//替換元素
boolean replace(K key, V oldValue, V newValue);
//替換元素
V replace(K key, V value);
}
- 「putIfAbsent:」如果插入的key相同,則不替換原有的value值;
- 「remove:」增加了對value的判斷,如果要刪除的key-value不能與Map中原有的key-value對應上,則不會刪除該元素;
- 「replace(K,V,V):」增加了對value值的判斷,如果key-oldValue能與Map中原有的key-value對應上,才進行替換操作;
- 「replace(K,V):」與上面的replace不同的是,此replace不會對Map中原有的key-value進行比較,如果key存在則直接替換;
ConcurrentHashMap
ConcurrentHashMap同HashMap一樣也是基于散列表的map
JDK 1.7
ConcurrentHashMap在JDK 1.7中,提供了一種粒度更細的加鎖機制來實現(xiàn)在多線程下更高的性能,這種機制叫分段鎖(Lock Striping)。
提供的優(yōu)點是:在并發(fā)環(huán)境下將實現(xiàn)更高的吞吐量,而在單線程環(huán)境下只損失非常小的性能。
分段鎖就是「將數(shù)據(jù)分段,對每一段數(shù)據(jù)分配一把鎖」。當一個線程占用鎖訪問其中一個段數(shù)據(jù)的時候,其他段的數(shù)據(jù)也能被其他線程訪問。
有些方法需要跨段,比如size()、isEmpty()、containsValue(),它們可能需要鎖定整個表而不僅僅是某個段,這需要按順序鎖定所有段,操作完畢后,又按順序釋放所有段的鎖
ConcurrentHashMap是由Segment數(shù)組結(jié)構(gòu)和HashEntry數(shù)組結(jié)構(gòu)組成。Segment是一種可重入鎖ReentrantLock,HashEntry則用于存儲鍵值對數(shù)據(jù)。
一個ConcurrentHashMap里包含一個Segment數(shù)組,Segment的結(jié)構(gòu)和HashMap類似,是一種數(shù)組和鏈表結(jié)構(gòu), 一個Segment里包含一個HashEntry數(shù)組,每個HashEntry是一個鏈表結(jié)構(gòu)的元素, 每個Segment守護著一個HashEntry數(shù)組里的元素,當對HashEntry數(shù)組的數(shù)據(jù)進行修改時,必須首先獲得它對應的Segment鎖。
JDK 1.8
而在JDK 1.8中,ConcurrentHashMap主要做了兩個優(yōu)化:
同HashMap一樣,鏈表也會在長度達到8的時候轉(zhuǎn)化為紅黑樹,這樣可以提升大量沖突時候的查詢效率;
以某個位置的頭結(jié)點(鏈表的頭結(jié)點或紅黑樹的root結(jié)點)為鎖,配合自旋+CAS避免不必要的鎖開銷,進一步提升并發(fā)性能。
ConcurrentNavigableMap接口與ConcurrentSkipListMap類
ConcurrentNavigableMap接口繼承了NavigableMap接口,這個接口提供了針對給定搜索目標返回最接近匹配項的導航方法。
ConcurrentNavigableMap接口的主要實現(xiàn)類是ConcurrentSkipListMap類。從名字上來看,它的底層使用的是跳表(SkipList)的數(shù)據(jù)結(jié)構(gòu)。它是一種”空間換時間“的數(shù)據(jù)結(jié)構(gòu),可以使用CAS來保證并發(fā)安全性。
并發(fā)Set
JDK提供了ConcurrentSkipListSet,是線程安全的有序的集合。底層是使用ConcurrentSkipListMap實現(xiàn)。
結(jié)束語
本節(jié)主要給大家講了同步容器和并發(fā)容器,在并發(fā)容器中,大家要重點關注ConcurrentHashMap,在本節(jié)中直接給大家講了它的機制,聽起來可能有點懵圈。
本文名稱:同步容器和并發(fā)容器有用過嗎?說說看
文章起源:http://fisionsoft.com.cn/article/djceejh.html


咨詢
建站咨詢
