Java併發工具類之CompletableFuture&StampedLock&ConcurrentSkipListMap

CompletableFuture

CompletableFuture是在Java8中引入的,擁有強大的功能,支持回調、工作流、異常處理等。CompletableFuture還是典型的Java8的工具類,有函數式編程、鏈式方法和語義化接口等.
除了Future接口,CompletableFuture還實現了CompletionStage接口。這個接口內容豐富,CompletableFuture的工作流功能,就是實現了這個接口。CompletionStage接口描述了任務之間的多種關係,包括:串行關係、並行關係、AND匯聚關係、OR匯聚關係。同時,支持這些關係的組合。


StampedLock

StampedLock是在Java8中引入的,是一種比ReadWriteLock更快的讀寫鎖。因爲,StampedLock對場景進行進一步的細分,把讀鎖分類爲悲觀讀鎖與樂觀讀,ReadWriteLock中的讀鎖類似於StampedLock的悲觀讀鎖。因此,StampedLock有三種模式:寫鎖、悲觀讀鎖與樂觀讀。
StampedLock之所以可以比ReadWrite更快,是因爲引入了樂觀讀(通過long tryOptimisticRead()與boolean validate(stamp)兩個方法實現的)。樂觀讀本質就是無鎖編程,使用樂觀讀性能好,就是因爲去掉了加鎖的性能開銷。

StampedLock使用的注意事項:
從功能上來說,StampedLock是ReadWriteLock的子集,StampedLock只是在讀多寫少的場景下,性能更優。StampedLock的使用存在着一些約束:

  • StampedLock是不可重入的,這從StampedLock沒有帶Reentrant可以看出來;
  • StampedLock不支持條件變量;
  • 使用StampedLock時,一定不要使用線程中斷方法,這會導致CPU飆升。

StampedLock用法參考:J.U.C之locks框架:StampedLock


ConcurrentSkipListMap

Map接口有兩個併發容器的實現類:ConcurrentHashMap和ConcurrentSkipListMap。併發Map內部使用的都是分段加鎖的,減小了鎖的粒度。相比於同步容器Hashtable,性能要高。ConcurrentHashMap和ConcurrentSkipListMap的區別在於,前者的key是無序的,後者是有序的。從命名就能看到實現原理,前者是Hash,後者是跳錶。跳錶這種數據結構,很好得實現了有序和時間複雜度之間的平衡。

使用ConcurrentHashMap和ConcurrentSkipListMap需要注意: 1. 二者都不支持key爲null,或value爲null; 2. 需要有序時使用後者。

Set接口也有兩個併發容器的實現類:CopyOnWriteArraySet和ConcurrentSkipListSet


線程安全的隊列使用建議

Java中可以用到的所有線程安全隊列,從是否阻塞、單雙端、是否有界、內部數據結構、是否無鎖及特殊功能這六個維度對隊列進行了對比,並詳細說明了各個隊列的特點及使用方式。

基於以上分析,我們對隊列的選擇建議如下:

按功能場景選擇需要的隊列

看是否需要阻塞接口,是否需要雙端; 需要支持handoff功能的,選擇LinkedTransferQueue或SynchronousQueue; 需要優先級出隊的,選擇PriorityBlockingQueue;需要延遲出隊的,選擇DelayQueue。

使用有界隊列

無界隊列可能出現OOM問題,這是一個致命問題。

ArrayBlockingQueue與LinkedBlockingQueue功能一致,建議使用ArrayBlockingQueue

ArrayBlockingQueue以數組爲基礎,長時間運行對GC壓力小,可能有效利用CPU緩存。長時間運行,效果好於LinkedBlockingQueue。

對吞吐量要求高的使用Disruptor

相比於ArrayBlockingQueue,Disruptor的吞吐量是其5到10倍。

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