三軍可奪帥也定庵,匹夫不可奪志也衰粹±妫———《論語》
上一篇講到同步容器類的潛在問題钦无,可以通過兩個方法解決污淋。
- 可以通過客戶端加鎖解決陨倡。
- 可以使用并發(fā)容器類來解決問題。
客戶端加鎖的方法我們已經(jīng)知道田篇,所以替废,這一篇介紹一下并發(fā)容器類原理,看它是如何解決這些問題的泊柬。
下面看下并發(fā)容器的框架圖:
我們從上圖可以看到椎镣,它們分為五大類:Map, List, Set,Collection,Queue, 同步容器類都是從這五大基類繼承而來兽赁,它們都是線程安全的状答。
同步容器類實現(xiàn)線程安全性的方式是所有方法都持有一個鎖,并發(fā)容器則不同刀崖,這里主要講介紹幾個并發(fā)容器類來說明惊科。
ConcurrentHashMap
它并不是每個方法都在同一個鎖上實現(xiàn)同步使得每次只能有一個線程訪問容器。而是使用一種粒度更細的加鎖機制來實現(xiàn)更大程度的共享亮钦,這種機制稱為分段鎖馆截。在這種機制中,任意數(shù)量的讀取線程可以并發(fā)訪問 Map,執(zhí)行讀取操作的線程和執(zhí)行寫入操作的線程可以并發(fā)的訪問 Map蜂莉,并且一定數(shù)量的寫入線程可以并發(fā)的修改 Map蜡娶。所以在并發(fā)環(huán)境中,它實現(xiàn)更高的吞吐量映穗,在單線程環(huán)境中損失非常小的性能窖张。
由于 ConcurrentHashMap 不能加鎖來執(zhí)行獨占訪問,因此我們無法通過客戶端加鎖來創(chuàng)建新的原子操作蚁滋。然而宿接,一些常見的復(fù)合操作已經(jīng)實現(xiàn)了赘淮。包括如下接口:
當你需要這些額外的原子操作時,那么你可以考慮使用它睦霎。
CopyOnWriteArrayList
寫時復(fù)制容器拥知,可以理解為向容器添加一個元素時,先將當前的容器進行復(fù)制碎赢,生成一個新的容器,然后在向新的容器添加元素速梗,之后再將原容器的引用指向新的容器肮塞。
好處是,對 CopyOnWrite 容器可以不用加鎖進行并發(fā)的讀姻锁,因為此時不會添加任何元素枕赵。CopyOnWrite 是一種讀寫分離的思想,讀操作和寫操作的是不同的容器位隶。
它可以用于替代同步 List拷窜,但是每次在修改容器時都會復(fù)制底層數(shù)組。比如 add(),set() 等操作時涧黄,需要一定的開銷篮昧,特別是當容器規(guī)模較大時,它比較適用于讀多寫少的并發(fā)場景笋妥。
ArrayBlockingQueue
它是數(shù)組實現(xiàn)的線程安全的有界的阻塞隊列(FIFO)懊昨,支持多任務(wù)并發(fā)操作。它內(nèi)部通過互斥鎖保護競爭資源春宣,實現(xiàn)了多線程對競爭資源的互斥訪問酵颁;有界是指數(shù)組的長度是固定的;阻塞是指當競爭資源已經(jīng)某線程獲取時月帝,其他要獲取該資源的線程需要阻塞等待躏惋。
它的核心函數(shù)都是通過可重入鎖 ReentrantLock 來確保線程同步的。包括 put(),offer(),take(),poll() 等嚷辅。同時簿姨,還包含兩個條件 Condition(notEmpty, notFull),加入元素是潦蝇,如果隊列已滿則必須等待款熬;取出元素時,如果隊列為空則必須等待攘乒。
總結(jié)
并發(fā)容器是針對多個線程并發(fā)訪問設(shè)計的贤牛,通過并發(fā)容器來代替同步容器,可以極大的提高伸縮性并降低風險则酝。并發(fā)容器提供的迭代不會拋出 ConcurrentModificationException殉簸,因此在迭代過程中不需要對容器加鎖闰集。另外,并發(fā)容器只能保證數(shù)據(jù)的最終一致性般卑,不能保證實時一致性武鲁。換句話說,容器被修改后的數(shù)據(jù)并不保證能夠?qū)崟r的反應(yīng)到迭代器的遍歷蝠检。
本文完結(jié)沐鼠,如果覺得有幫助,請關(guān)注我叹谁,謝謝饲梭!
參考
- 《Java并發(fā)編程實戰(zhàn)》
- http://www.cnblogs.com/leesf456/p/5428630.html