日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

高并发第八弹:J.U.C起航(java.util.concurrent)

發布時間:2025/7/14 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 高并发第八弹:J.U.C起航(java.util.concurrent) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

java.util.concurrent是JDK自帶的一個并發的包主要分為以下5部分:

  • 并發工具類(tools)
  • 顯示鎖(locks)
  • 原子變量類(aotmic)
  • 并發集合(collections)
  • Executor線程執行器

我們今天就說說 并發集合,除開 Queue,放在線程池的時候講

先介紹以下 CopyOnWrite:

Copy-On-Write簡稱COW,是一種用于程序設計中的優化策略。其基本思路是,從一開始大家都在共享同一個內容,當某個人想要修改這個內容的時候,才會真正把內容Copy出去形成一個新的內容然后再改,這是一種延時懶惰策略。從JDK1.5開始Java并發包里提供了兩個使用CopyOnWrite機制實現的并發容器,它們是CopyOnWriteArrayList和CopyOnWriteArraySet。CopyOnWrite容器非常有用,可以在非常多的并發場景中使用到?.

CopyOnWrite容器即寫時復制的容器。通俗的理解是當我們往一個容器添加元素的時候,不直接往當前容器添加,而是先將當前容器進行Copy,復制出一個新的容器,然后新的容器里添加元素,添加完元素之后,再將原容器的引用指向新的容器。這樣做的好處是我們可以對CopyOnWrite容器進行并發的讀,而不需要加鎖,因為當前容器不會添加任何元素。所以CopyOnWrite容器也是一種讀寫分離的思想,讀和寫不同的容器。

public class CopyOnWriteArrayList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable {private static final long serialVersionUID = 8673264195747942595L;/** The lock protecting all mutators */final transient ReentrantLock lock = new ReentrantLock();/** The array, accessed only via getArray/setArray. */private transient volatile Object[] array;............................
public boolean add(E e) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();//獲取當前數組數據int len = elements.length;Object[] newElements = Arrays.copyOf(elements, len + 1); //復制當前數組并且擴容+1newElements[len] = e;setArray(newElements);//將原來的數組指向新的數組return true;} finally {lock.unlock();}}

?

下面這篇文章驗證了CopyOnWriteArrayList和同步容器的性能:

  http://blog.csdn.net/wind5shy/article/details/5396887

  下面這篇文章簡單描述了CopyOnWriteArrayList的使用:

  http://blog.csdn.net/imzoer/article/details/9751591

?

因為 網友總結的優缺點是:

    • 缺點:?
      1.寫操作時復制消耗內存,如果元素比較多時候,容易導致young gc 和full gc。?
      2.不能用于實時讀的場景.由于復制和add操作等需要時間,故讀取時可能讀到舊值。?
      能做到最終一致性,但無法滿足實時性的要求,更適合讀多寫少的場景。?
      如果無法知道數組有多大,或者add,set操作有多少,慎用此類,在大量的復制副本的過程中很容易出錯。

    • 設計思想:?
      1.讀寫分離?
      2.最終一致性?
      3.使用時另外開辟空間,防止并發沖突

這個還真是主要是針對 讀多的條件.畢竟寫一個就要開辟一個空間.太耗資源了.其實還是建議用手動的方式來控制集合的并發.

1.?ArrayList –> CopyOnWriteArrayList

它相當于線程安全的ArrayList。和ArrayList一樣,它是個可變數組;但是和ArrayList不同的時,它具有以下特性:
1. 它最適合于具有以下特征的應用程序:List 大小通常保持很小,只讀操作遠多于可變操作,需要在遍歷期間防止線程間的沖突。
2. 它是線程安全的。
3. 因為通常需要復制整個基礎數組,所以可變操作(add()、set() 和 remove() 等等)的開銷很大。
4. 迭代器支持hasNext(), next()等不可變操作,但不支持可變 remove()等操作。
5. 使用迭代器進行遍歷的速度很快,并且不會與其他線程發生沖突。在構造迭代器時,迭代器依賴于不變的數組快照。

?2.?HashSet –> CopyOnWriteArraySet

它是線程安全的無序的集合,可以將它理解成線程安全的HashSet。有意思的是,CopyOnWriteArraySet和HashSet雖然都繼承于共同的父類AbstractSet;但是,HashSet是通過“散列表(HashMap)”實現的,而CopyOnWriteArraySet則是通過“動態數組(CopyOnWriteArrayList)”實現的,并不是散列表。
和CopyOnWriteArrayList類似,CopyOnWriteArraySet具有以下特性:
1. 它最適合于具有以下特征的應用程序:Set 大小通常保持很小,只讀操作遠多于可變操作,需要在遍歷期間防止線程間的沖突。
2. 它是線程安全的。
3. 因為通常需要復制整個基礎數組,所以可變操作(add()、set() 和 remove() 等等)的開銷很大。
4. 迭代器支持hasNext(), next()等不可變操作,但不支持可變 remove()等 操作。
5. 使用迭代器進行遍歷的速度很快,并且不會與其他線程發生沖突。在構造迭代器時,迭代器依賴于不變的數組快照。

?

SkipList 跳表:先介紹這個吧

介紹的很詳細?https://blog.csdn.net/sunxianghuang/article/details/52221913

更優秀的 :https://www.cnblogs.com/skywang12345/p/3498556.html

?

總結起來就是:

  傳統意義的單鏈表是一個線性結構,向有序的鏈表中插入一個節點需要O(n)的時間,查找操作需要O(n)的時間

  跳表查找的復雜度為O(n/2)。跳躍表其實也是一種通過“空間來換取時間”的一個算法,通過在每個節點中增加了向前的指針,從而提升查找的效率。

?

先以數據“7,14,21,32,37,71,85”序列為例,來對跳表進行簡單說明。

跳表分為許多層(level),每一層都可以看作是數據的索引,這些索引的意義就是加快跳表查找數據速度。每一層的數據都是有序的,上一層數據是下一層數據的子集,并且第一層(level 1)包含了全部的數據;層次越高,跳躍性越大,包含的數據越少。
跳表包含一個表頭,它查找數據時,是從上往下,從左往右進行查找?,F在“需要找出值為32的節點”為例,來對比說明跳表和普遍的鏈表。

情況1:鏈表中查找“32”節點
路徑如下圖1-02所示:

需要4步(紅色部分表示路徑)。

?

情況2:跳表中查找“32”節點
路徑如下圖1-03所示:

忽略索引垂直線路上路徑的情況下,只需要2步(紅色部分表示路徑)。

先以數據“7,14,21,32,37,71,85”序列為例,來對跳表進行簡單說明。

跳表分為許多層(level),每一層都可以看作是數據的索引,這些索引的意義就是加快跳表查找數據速度。每一層的數據都是有序的,上一層數據是下一層數據的子集,并且第一層(level 1)包含了全部的數據;層次越高,跳躍性越大,包含的數據越少。
跳表包含一個表頭,它查找數據時,是從上往下,從左往右進行查找?,F在“需要找出值為32的節點”為例,來對比說明跳表和普遍的鏈表。

情況1:鏈表中查找“32”節點
路徑如下圖1-02所示:

需要4步(紅色部分表示路徑)。

?

情況2:跳表中查找“32”節點
路徑如下圖1-03所示:

忽略索引垂直線路上路徑的情況下,只需要2步(紅色部分表示路徑)。

3.?TreeMap –> ConcurrentSkipListMap

下面說說Java中ConcurrentSkipListMap的數據結構。
(01) ConcurrentSkipListMap繼承于AbstractMap類,也就意味著它是一個哈希表。
(02) Index是ConcurrentSkipListMap的內部類,它與“跳表中的索引相對應”。HeadIndex繼承于Index,ConcurrentSkipListMap中含有一個HeadIndex的對象head,head是“跳表的表頭”。
(03) Index是跳表中的索引,它包含“右索引的指針(right)”,“下索引的指針(down)”和“哈希表節點node”。node是Node的對象,Node也是ConcurrentSkipListMap中的內部類。

?

/*** Special value used to identify base-level header*/private static final Object BASE_HEADER = new Object();/*** 跳表的最頂層索引*/private transient volatile HeadIndex<K,V> head;/*** * 比較器用于維護此映射中的順序,或者如果使用自然排序,則為空。(非私有的,以* 簡化嵌套類中的訪問)。* */final Comparator<? super K> comparator;/** Lazily initialized key set */ //懶惰初始化密鑰集private transient KeySet<K> keySet;/** Lazily initialized entry set */private transient EntrySet<K,V> entrySet;/** Lazily initialized values collection */private transient Values<V> values;/** Lazily initialized descending key set */

源碼我也沒精力去詳勘了.就總結一下

?

4.?TreeSet –> ConcurrentSkipListSet

(01) ConcurrentSkipListSet繼承于AbstractSet。因此,它本質上是一個集合。
(02) ConcurrentSkipListSet實現了NavigableSet接口。因此,ConcurrentSkipListSet是一個有序的集合。
(03) ConcurrentSkipListSet是通過ConcurrentSkipListMap實現的。它包含一個ConcurrentNavigableMap對象m,而m對象實際上是ConcurrentNavigableMap的實現類ConcurrentSkipListMap的實例。ConcurrentSkipListMap中的元素是key-value鍵值對;而ConcurrentSkipListSet是集合,它只用到了ConcurrentSkipListMap中的key!

(4)同其他set集合,是基于map集合的(基于ConcurrentSkipListMap),在多線程環境下,里面的contains、add、remove操作都是線程安全的。

?(5)多個線程可以安全的并發的執行插入、移除、和訪問操作。但是對于批量操作addAll、removeAll、retainAll和containsAll并不能保證以原子方式執行,原因是addAll、removeAll、retainAll底層調用的還是  contains、add、remove方法,只能保證每一次的執行是原子性的,代表在單一執行操縱時不會被打斷,但是不能保證每一次批量操作都不會被打斷。在使用批量操作時,還是需要手動加上同步操作的。

(6)不允許使用null元素的,它無法可靠的將參數及返回值與不存在的元素區分開來。

?

5.??HashMap –> ConcurrentHashMap

  • 不允許空值,在實際的應用中除了少數的插入操作和刪除操作外,絕大多數我們使用map都是讀取操作。而且讀操作大多數都是成功的。基于這個前提,它針對讀操作做了大量的優化。因此這個類在高并發環境下有特別好的表現。
  • ConcurrentHashMap作為Concurrent一族,其有著高效地并發操作,相比Hashtable的笨重,ConcurrentHashMap則更勝一籌了。
  • 在1.8版本以前,ConcurrentHashMap采用分段鎖的概念,使鎖更加細化,但是1.8已經改變了這種思路,而是利用CAS+Synchronized來保證并發更新的安全,當然底層采用數組+鏈表+紅黑樹的存儲結構。
  • 源碼分析:推薦參考chenssy的博文:J.U.C之Java并發容器:ConcurrentHashMap

?

安全共享對象策略
  • 線程限制:一個被線程限制的對象,由線程獨占,并且只能被占有它的線程修改
  • 共享只讀:一個共享只讀的U帝鄉,在沒有額外同步的情況下,可以被多個線程并發訪問,但是任何線程都不能修改它
  • 線程安全對象:一個線程安全的對象或者容器,在內部通過同步機制來保障線程安全,多以其他線程無需額外的同步就可以通過公共接口隨意訪問他
  • 被守護對象:被守護對象只能通過獲取特定的鎖來訪問。

?

不好意思 虎頭蛇尾了.實在扛不住了

轉載于:https://www.cnblogs.com/aihuxi/p/9683805.html

總結

以上是生活随笔為你收集整理的高并发第八弹:J.U.C起航(java.util.concurrent)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。