java併發——併發容器

同步容器 & 併發容器
1. 同步容器。同步容器只有包括Vector和HashTable,如果你覺得陌生,那就對了,二者事早期JDK就有的,在java.util包下面,和同包下的其他不能保證同步安全的容器類相比顯得鶴立雞羣,但是它們的技術相比其他容器累只是多用了Synchronize的技術,下面的併發容器,算法和底層技術上做了改進,並且在容器的併發操作方面有諸多優化,性能更優,所以知道這對難兄難弟就好,實戰千萬不要用哦;
2. 併發容器。併發容器是java 5.0開始提供的,在java.util.concurrent包下。一個東西的好一定是比較出來的,同步容器實現的線程安全性簡單粗暴,把所有對容器狀態的操作串行化,併發容器針對各種容器的特定功能,採用最佳的設計,比如BlockingQueue的讀寫分離鎖、阻塞訪問、定時阻塞,ConcurrentHashMap的分段鎖,CopyOnWriteArraySet的寫入時複製,下面會逐一介紹它們的詳細功能以及應用場所。

細說併發容器
java 5.0增加了兩種新的容器類型,Queue和BlockingQueue,隊列的特點是先進先出,插入和移除操作分別僅能在隊列的兩端操作。BlockingQueue比Queue多了put、take、offer和poll,他們分別是阻塞插入、阻塞移除、定時阻塞插入和定時阻塞移除。
事實上,Queue是通過LinkedList實現的(隊列的修改操作僅限首尾端,用鏈表比數組更好),因爲它能去掉List的隨機訪問功能,從而實現了更高效的開發,封裝性更好。
1. ConCurrentLinkedQueue
插入和移除具有線程安全的一個隊列實現類。當只有隊列+併發的需求,就是它了;
2. LinkedBlockingQueue
使用很廣泛的一個類,因爲真的很實用啊。LinkedBlockingQueue滿足隊列+併發+阻塞訪問的需求,是生產者-消費者模型的最佳實現對象,當然,如果有Priority這樣的需求,可以在LinkedBlockingQueue基礎上開發;
3. ConcurrentHashMap
使用HashMap,任何說需要增加併發需求的情況下,那一定是ConcurrentHashMap了,ConcurrentHashMap使用鎖控制線程併發訪問,同時分段鎖機制確保了併發訪問不會是性能損失很大。
ConcurrentHashMap
不同的線程可以同時訪問ConcurrentHashMap下不同的HashMap,當然HashMap的讀寫是保證線程安全的,這個設計兼顧了併發和性能兩個要素;
4. CopyOnWriteArrayList,CopyOnWriteArraySet
帶有“CopyOnWriteArray“關鍵字的容器,具有寫入時複製的特點。寫入時複製,能夠權衡兩個問題,容器迭代操作引發的併發問題,和容器迭代使用鎖而帶來的性能損耗。非同步、併發的容器進行迭代操作,會拋出一個運行時異常ConcurrentModificationException,雖然運行時異常並不要求上層代碼一定要處理,但並不代表應該忽視這種情況。
容器迭代操作引發的併發問題。非同步、併發的容器迭代過程,容器就有可能被修改,因此next(),hasNext()方法都要執行checkForComodification操作,ConcurrentModificationException異常也僅在於告知上層代碼有併發的存在,並不會處理。

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

容器迭代使用鎖而帶來的性能損耗。同步類和併發類的迭代功能,會持有容器的鎖確保迭代不會有併發問題,這裏有個例外是ConcurrentHashMap,雖然迭代ConcurrentHashMap也會持有鎖,奈何ConcurrentHashMap鎖不止一個,能夠確保迭代併發性的大概也只有最有一個被迭代的HashMap。當容器的容量很大時,迭代將長時間佔着鎖,其他的線程苦不堪言,因此迭代會讓大容量的併發容器性能大打折扣。
寫入時複製。“寫入時複製“容器會維護兩套數據,修改是一套,查詢是一套,當修改是會把修改內容更新到副本。那麼迭代過程就不需要持鎖訪問容器了,是不是很簡單粗暴。
copyOnWriteArray
顯然,每當修改容器時都會複製底層數組,這需要一定的開銷,特別是當容器規模特別大的時。僅當迭代操作遠遠大於修改操作時,才應該使用“寫入時複製“容器。
5. Deque,BlockingDeque
java 6.0增加了兩種容器類型,Deque(發音爲“deck“)和BlockingDeque,它們分別對Queue和BlockingQueue做了擴展,能夠在隊列兩端進行插入和移除操作,稱爲雙端隊列。
在隊列兩端開放插入和移除功能並非多此一舉,在工作密取模式中,Deque能夠很好的工作。在生產者-消費者設計中,所有消費者共享一個工作隊列,而在工作密取設計中,每組生產者消費者有各自的雙端隊列,當它們完成了自己的工作,可以到其他組的尾端工作。工作密取模式比生產者消費者模式有更好的伸縮性,這是因爲工作者線程不會在單個共享的任務隊列發生競爭。雙端隊列很適合用在爬蟲這樣的工作中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章