同步容器與并發(fā)容器

一英支、同步容器

1. 實(shí)現(xiàn)原理

同步容器可以簡(jiǎn)單地理解為通過(guò) synchronized 來(lái)實(shí)現(xiàn)同步的容器前硫,如果有多個(gè)線程調(diào)用同步容器的方法锥咸,它們將會(huì)串行執(zhí)行输硝。

2. 分類

同步容器將它們的狀態(tài)封裝起來(lái),并對(duì)每一個(gè)公有方法進(jìn)行同步党窜。主要包括:

  • Vector
  • Stack
  • HashTable
  • Collections 工具類中部分方法生成,例如:
    • Collectinons.synchronizedList()
    • Collections.synchronizedSet()
    • Collections.synchronizedMap()
    • Collections.synchronizedSortedSet()
    • Collections.synchronizedSortedMap()

其中 Vector(同步的ArrayList)和 Stack(繼承自Vector借宵,先進(jìn)后出)幌衣、HashTable(繼承自 Dictionary,實(shí)現(xiàn)了 Map 接口)是比較老的容器,Thinking in Java 中明確指出豁护,這些容器現(xiàn)在仍然存在于 JDK 中是為了向以前老版本的程序兼容哼凯,在新的程序中不應(yīng)該在使用。Collections的方法時(shí)將非同步的容器包裹生成對(duì)應(yīng)的同步容器楚里。

同步容器在單線程的環(huán)境下能夠保證線程安全断部,但是通過(guò) synchronized 同步方法將訪問(wèn)操作串行化,導(dǎo)致并發(fā)環(huán)境下效率低下班缎。而且同步容器在多線程環(huán)境下的復(fù)合操作(迭代蝴光、條件運(yùn)算如沒(méi)有則添加等)是非線程安全,需要客戶端代碼來(lái)實(shí)現(xiàn)加鎖达址。

3. 代碼示例
public static Object getLast(Vector list) {
    int lastIndex = list.size() - 1;
    return list.get(lastIndex);
}
 
public static void deleteLast(Vector list) {
    int lastIndex = list.size() - 1;
    list.remove(lastIndex);
}

上面的代碼取最后一個(gè)元素或者刪除最后一個(gè)元素蔑祟,使用了同步容器 Vector。如果有兩個(gè)線程 A 和 B 同時(shí)調(diào)用上面的兩個(gè)方法沉唠,假設(shè) list 的大小為 10疆虚,這里計(jì)算得到的 lastIndex 為 9,線程 B 首先執(zhí)行了刪除操作(多線程之間操作執(zhí)行的不確定性導(dǎo)致)满葛,而后線程 A 調(diào)用了 list.get 方法径簿,這時(shí)就會(huì)發(fā)生數(shù)組越界異常,導(dǎo)致問(wèn)題的原因就是上面的復(fù)合操作不是原子操作嘀韧,這里可以通過(guò)在方法內(nèi)部額外的使用 list 對(duì)象鎖來(lái)實(shí)現(xiàn)原子操作篇亭。

在多線程中使用同步容器,如果使用 Iterator 迭代容器或使用使用 for-each 遍歷容器乳蛾,在迭代過(guò)程中修改容器會(huì)拋出 ConcurrentModificationException 異常暗赶。想要避免出現(xiàn) ConcurrentModificationException,就必須在迭代過(guò)程持有容器的鎖肃叶。但是若容器較大蹂随,則迭代的時(shí)間也會(huì)較長(zhǎng)。那么需要訪問(wèn)該容器的其他線程將會(huì)長(zhǎng)時(shí)間等待因惭。從而會(huì)極大降低性能岳锁。

此外,隱式迭代的情況蹦魔,如 toString激率、hashCodeequals勿决、containsAll等限、removeAllretainAll 等方法都會(huì)隱式的 Iterator 均牢,也可能拋出 ConcurrentModificationException涩禀。

二曹货、并發(fā)容器

1. 實(shí)現(xiàn)原理

同步容器并不能保證多線程安全,而并發(fā)容器是針對(duì)多個(gè)線程并發(fā)訪問(wèn)而設(shè)計(jì)的讳推。在 JDK 1.5 中引入了concurrent包顶籽,其中提供了很多并發(fā)容器,極大的提升同步容器類的性能银觅。

2. 分類

ConcurrentHashMap

  • 對(duì)應(yīng)的非并發(fā)容器:HashMap
  • 目標(biāo):代替Hashtable礼饱、synchronizedMap,支持復(fù)合操作
  • 原理:JDK 1.6 中采用一種更加細(xì)粒度的加鎖機(jī)制 Segment 分段鎖究驴,JDK 1.8 中采用 CAS 無(wú)鎖算法镊绪。

CopyOnWriteArrayList

  • 對(duì)應(yīng)的非并發(fā)容器:ArrayList
  • 目標(biāo):代替Vector、synchronizedList
  • 原理:利用高并發(fā)往往是讀多寫(xiě)少的特性纳胧,讀操作不加鎖镰吆;寫(xiě)操作先復(fù)制一份新的集合,在新的集合上面修改跑慕,然后將新集合賦值給舊的引用万皿,并通過(guò) volatile 保證其可見(jiàn)性,當(dāng)然寫(xiě)操作的鎖是必不可少的了核行。

CopyOnWriteArraySet

  • 對(duì)應(yīng)的非并發(fā)容器:HashSet
  • 目標(biāo):代替 synchronizedSet
  • 原理:基于 CopyOnWriteArrayList 實(shí)現(xiàn)牢硅,其唯一的不同是在 add 時(shí)調(diào)用的是 CopyOnWriteArrayList 的 addIfAbsent 方法,其遍歷當(dāng)前 Object 數(shù)組芝雪,如 Object 數(shù)組中已有了當(dāng)前元素减余,則直接返回;如果沒(méi)有則放入 Object 數(shù)組的尾部惩系,并返回位岔。

ConcurrentSkipListMap

  • 對(duì)應(yīng)的非并發(fā)容器:TreeMap
  • 目標(biāo):代替 synchronizedSortedMap(TreeMap)
  • 原理:Skip List(跳表)是一種可以代替平衡樹(shù)的數(shù)據(jù)結(jié)構(gòu),默認(rèn)是按照 Key 值升序的堡牡。Skip List 讓已排序的數(shù)據(jù)分布在多層鏈表中抒抬,以 0 - 1 隨機(jī)數(shù)決定一個(gè)數(shù)據(jù)的向上攀升與否,通過(guò) 空間來(lái)?yè)Q取時(shí)間 的一個(gè)算法晤柄。ConcurrentSkipListMap 提供了一種線程安全的并發(fā)訪問(wèn)的排序映射表擦剑。內(nèi)部是 Skip List結(jié)構(gòu)實(shí)現(xiàn),在理論上能夠在 O(log(n)) 時(shí)間內(nèi)完成查找芥颈、插入惠勒、刪除操作。

ConcurrentSkipListSet

  • 對(duì)應(yīng)的非并發(fā)容器:TreeSet
  • 目標(biāo):代替 synchronizedSortedSet
  • 原理:內(nèi)部基于 ConcurrentSkipListMap 實(shí)現(xiàn)

ConcurrentLinkedQueue

  • 對(duì)應(yīng)的非并發(fā)容器:Queue
  • 原理:不會(huì)阻塞的隊(duì)列爬坑,基于鏈表實(shí)現(xiàn)的 FIFO 隊(duì)列(LinkedList 的并發(fā)版本)

LinkedBlockingQueue纠屋、ArrayBlockingQueue、PriorityBlockingQueue

  • 對(duì)應(yīng)的并發(fā)容器:Queue
  • 特點(diǎn):拓展了Queue盾计,增加了可阻塞的插入和獲取等操作
  • 原理:通過(guò) ReentrantLock 實(shí)現(xiàn)線程安全巾遭,通過(guò) Condition 實(shí)現(xiàn)阻塞和喚醒
  • LinkedBlockingQueue:基于鏈表實(shí)現(xiàn)的可阻塞的 FIFO 隊(duì)列
  • ArrayBlockingQueue:基于數(shù)組實(shí)現(xiàn)的可阻塞的 FIFO 隊(duì)列
  • PriorityBlockingQueue:按優(yōu)先級(jí)排序的隊(duì)列
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肉康,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子灼舍,更是在濱河造成了極大的恐慌,老刑警劉巖涨薪,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骑素,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡刚夺,警方通過(guò)查閱死者的電腦和手機(jī)献丑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)侠姑,“玉大人创橄,你說(shuō)我怎么就攤上這事∶Ш欤” “怎么了妥畏?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)安吁。 經(jīng)常有香客問(wèn)我醉蚁,道長(zhǎng),這世上最難降的妖魔是什么鬼店? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任网棍,我火速辦了婚禮,結(jié)果婚禮上妇智,老公的妹妹穿的比我還像新娘滥玷。我一直安慰自己,他們只是感情好巍棱,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布惑畴。 她就那樣靜靜地躺著,像睡著了一般拉盾。 火紅的嫁衣襯著肌膚如雪桨菜。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天捉偏,我揣著相機(jī)與錄音倒得,去河邊找鬼。 笑死夭禽,一個(gè)胖子當(dāng)著我的面吹牛霞掺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播讹躯,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼菩彬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼缠劝!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起骗灶,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤惨恭,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后耙旦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體脱羡,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年免都,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锉罐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绕娘,死狀恐怖脓规,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情险领,我是刑警寧澤侨舆,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站舷暮,受9級(jí)特大地震影響态罪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜下面,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一复颈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沥割,春花似錦耗啦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至椒拗,卻和暖如春似将,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蚀苛。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工在验, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人堵未。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓腋舌,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親渗蟹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子块饺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容