多線程—併發容器與機制

fail-fast 機制

一種錯誤檢測機制。常見的使用fail-fast方式遍歷的容器有HashMap和ArrayList等。當在迭代集合的過程中該集合在結構上發生改變的時候,比如單線程遍歷時remove(),多線程一個讀取數據一個操作數據,就有可能會發生fail-fast,即拋出ConcurrentModificationException異常。

fail-safe 機制

先複製原有集合內容,在拷貝的集合上進行遍歷,所以在遍歷過程中對原集合所作的修改並不能被迭代器檢測到,不會觸發Concurrent Modification Exception。java.util.concurrent包下的容器都是fail-safe機制,可以在多線程下併發使用,併發修改。

同步容器  

在Java中,同步容器主要包括2類:

  • Vector、Stack、HashTable
  • Collections類中提供的靜態工廠方法創建的類

缺點:

同步容器效率低,fail-fast機制,對同步容器進行迭代的同時修改它的內容,會報ConcurrentModificationException異常。

阻塞隊列與非阻塞隊列

阻塞隊列:當隊列滿時,隊列會阻塞插入元素的線程,直到隊列不滿;當隊列爲空時,隊列會阻塞獲取元素的線程,直到隊列不空。

非阻塞隊列:若線程從中獲取元素,若沒有則直接返回空,不會阻塞當前線程

分段鎖

簡單來說就是將數據進行分段,每一段鎖用於鎖容器中的一部分數據,那麼當多線程訪問容器裏的不容數據段的數據時,線程間就不會存在鎖競爭,從而可以有效地提高併發訪問效率。有些方法需要跨段,比如size(),就需要按照順序鎖定所有的段,完成操作後,再按順序釋放鎖。

併發容器

採用fail-safe機制。

非阻塞隊列

CopyOnWriteArrayList

  • 讀寫分離,讀操作不加鎖,所有線程都不會阻塞。寫操作加鎖,線程會阻塞。
  • 寫線程獲取到鎖,其他線程包括讀線程阻塞
  • 實現方式是寫時複製出一個新的數組,完成插入、修改或者移除操作後將新數組賦值給array。
  • 適用於讀遠遠大於寫的時候。

ConcurrentHashMap 
多線程環境下,使用Hashmap進行put操作可能會引起死循環。

  • Hashtable實現同步是利用synchronized關鍵字進行鎖定的,其是針對整張哈希表進行鎖定的,即每次鎖住整張表讓線程獨佔,在線程安全的背後是巨大的浪費。
  • ConcurrentHashMap採用分段鎖,單獨鎖住每一個桶(segment),ConcurrentHashMap將哈希表分爲16個桶(默認值),get(),put(),remove()等常用操作只鎖當前需要用到的桶。原來只能一個線程進入,現在卻能同時接受16個寫線程併發進入。有些方法需要跨段,比如size()和containsValue(),它們可能需要鎖定整個表,這需要按順序鎖定所有段,操作完畢後,又按順序釋放所有段的鎖。這裏“按順序”是很重要的,否則極有可能出現死鎖。

ConcurrentLinkedQueue

  • 一個基於鏈接節點的無界線程安全隊列。
  • 此隊列按照 FIFO(先進先出)原則對元素進行排序,新的元素插入到隊列的尾部,隊列獲取操作從隊列頭部獲得元素。
  • 它的主要api是offer和poll, offer將指定元素插入此隊列的尾部 ;poll 獲取並移除此隊列的頭,如果此隊列爲空,則返回 null。

阻塞隊列BlockingQueue

在線程池中有所運用,獲取不到任務就一直處於阻塞狀態。

ArrayBlockingQueue

  • 基於數組的阻塞隊列實現,在ArrayBlockingQueue內部,維護了一個定長數組,以便緩存隊列中的數據對象,這是一個常用的阻塞隊列。
  • ArrayBlockingQueue內部保存着兩個整形變量,分別標識着隊列的頭部和尾部在數組中的位置。

LinkedBlockingQueue

  • 基於鏈表的阻塞隊列,同ArrayListBlockingQueue類似,其內部也維持着一個數據緩衝隊列(該隊列由一個鏈表構成),當生產者往隊列中放入一個數據時,隊列會從生產者手中獲取數據,並緩存在隊列內部,而生產者立即返回;只有當隊列緩衝區達到最大值緩存容量時(LinkedBlockingQueue可以通過構造函數指定該值),纔會阻塞生產者隊列,直到消費者從隊列中消費掉一份數據,生產者線程會被喚醒,反之對於消費者這端的處理也基於同樣的原理。
  • 沒有指定其容量大小,LinkedBlockingQueue會默認一個類似無限大小的容量(Integer.MAX_VALUE)

PriorityBlockingQueue

支持優先級的無界阻塞隊列,默認情況下元素按照自然順序升序排列,可以自定義類實現compareTo()方法來指定元素的排序規則,或在初始化PriorityBlockingQueue時指定構造參數Comparator來對元素進行排序,但不能保證同優先級元素的順序;
 

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