1、CopyOnWriteArrayList數組
製做數組的乾淨複本是一項成本極高的操做,在時間和內存這兩方面均有開銷,以致於在一般的應用中不能考慮該方法;開發者經常求助於使用同步的 ArrayList來替代前述方法。但這也是一個比較有代價的選項,由於當每次你遍歷訪問該集合中的內容時,你不得不一樣步全部的方法,包括讀和寫,以確保內存一致性。 在有大量用戶在讀取ArrayList而只有不多用戶對其進行修改的這一場景中,上述方法將使成本結構變得緩慢。 CopyOnWriteArrayList就是解決這一問題的一個極好的寶貝工具。它的Javadoc描述到,ArrayList經過建立數組的乾淨復原本實現可變操做(添加,修改,等等),而CopyOnWriteArrayList則是ArrayList的一個"線程安全"的變體。 對於任何修改操做,該集合類會在內部將其內容複製到一個新數組中,因此當讀用戶訪問數組的內容時不會招致任何同步開銷(由於它們沒有對可變數據進行操做)。 本質上,建立CopyOnWriteArrayList的想法,是出於應對當ArrayList沒法知足咱們要求時的場景:常常讀,而不多寫的集合對象,例如針對JavaBean事件的Listener。安全
用途:讀多寫少,ArrayList(讀 不加鎖) Vector(寫 加鎖)數據結構
2、ConcurrentHashMap併發
ConcurrentHashMap和Hashtable主要區別就是圍繞着鎖的粒度以及如何鎖。如圖
左邊即是Hashtable的實現方式---鎖整個hash表;而右邊則是ConcurrentHashMap的實現方式---鎖桶(或段)。ConcurrentHashMap將hash表分爲16個桶(默認值),諸如get,put,remove等經常使用操做只鎖當前須要用到的桶。試想,原來只能一個線程進入,如今卻能同時16個寫線程進入(寫線程才須要鎖定,而讀線程幾乎不受限制,以後會提到),併發性的提高是顯而易見的。
更使人驚訝的是ConcurrentHashMap的讀取併發,由於在讀取的大多數時候都沒有用到鎖定,因此讀取操做幾乎是徹底的併發操做,而寫操做鎖定的粒度又很是細,比起以前又更加快速(這一點在桶更多時表現得更明顯些)。只有在求size等操做時才須要鎖定整個表。而在迭代時,ConcurrentHashMap使用了不一樣於傳統集合的快速失敗迭代器(見以前的文章《JAVA API備忘---集合》)的另外一種迭代方式,咱們稱爲弱一致迭代器。在這種迭代方式中,當iterator被建立後集合再發生改變就再也不是拋出ConcurrentModificationException,取而代之的是在改變時new新的數據從而不影響原有的數據,iterator完成後再將頭指針替換爲新的數據,這樣iterator線程可使用原來老的數據,而寫線程也能夠併發的完成改變,更重要的,這保證了多個線程併發執行的連續性和擴展性,是性能提高的關鍵。
接下來,讓咱們看看ConcurrentHashMap中的幾個重要方法,內心知道了實現機制後,使用起來就更加有底氣。
ConcurrentHashMap中主要實體類就是三個:ConcurrentHashMap(整個Hash表),Segment(桶),HashEntry(節點),對應上面的圖能夠看出之間的關係。 函數
注意:工具
ConcurrentHashMap,不要輕易用.size(),由於它會鎖整張表;性能
ConcurrentHashMap,不要輕易用.remove(),由於它會涉及到hashTable中該entry以前的全部元素都要進行拷貝操做(爲何要拷貝呢?由於entry除了value字段是變量外,其餘都是final的,這樣索引的時候不用同步,性能更快)spa
用途:讀多寫少,HashMap(讀 不加鎖) Hashtable(寫 加鎖)線程
3、BlockingQueue指針
BlockingQueue,若是BlockQueue是空的,從BlockingQueue取東西的操做將會被阻斷進入等待狀態,直到BlockingQueue進了東西纔會被喚醒.一樣,若是BlockingQueue是滿的,任何試圖往裏存東西的操做也會被阻斷進入等待狀態,直到BlockingQueue裏有空間纔會被喚醒繼續操做.
使用BlockingQueue的關鍵技術點以下:
1.BlockingQueue定義的經常使用方法以下:
1)add(anObject):把anObject加到BlockingQueue裏,即若是BlockingQueue能夠容納,則返回true,不然招聘異常
2)offer(anObject):表示若是可能的話,將anObject加到BlockingQueue裏,即若是BlockingQueue能夠容納,則返回true,不然返回false.
3)put(anObject):把anObject加到BlockingQueue裏,若是BlockQueue沒有空間,則調用此方法的線程被阻斷直到BlockingQueue裏面有空間再繼續.
4)poll(time):取走BlockingQueue裏排在首位的對象,若不能當即取出,則能夠等time參數規定的時間,取不到時返回null
5)take():取走BlockingQueue裏排在首位的對象,若BlockingQueue爲空,阻斷進入等待狀態直到Blocking有新的對象被加入爲止
2.BlockingQueue有四個具體的實現類,根據不一樣需求,選擇不一樣的實現類
1)ArrayBlockingQueue:規定大小的BlockingQueue,其構造函數必須帶一個int參數來指明其大小.其所含的對象是以FIFO(先入先出)順序排序的.
2)LinkedBlockingQueue:大小不定的BlockingQueue,若其構造函數帶一個規定大小的參數,生成的BlockingQueue有大小限制,若不帶大小參數,所生成的BlockingQueue的大小由Integer.MAX_VALUE來決定.其所含的對象是以FIFO(先入先出)順序排序的
3)PriorityBlockingQueue:相似於LinkedBlockQueue,但其所含對象的排序不是FIFO,而是依據對象的天然排序順序或者是構造函數的Comparator決定的順序.
4)SynchronousQueue:特殊的BlockingQueue,對其的操做必須是放和取交替完成的.
3.LinkedBlockingQueue和ArrayBlockingQueue比較起來,它們背後所用的數據結構不同,致使LinkedBlockingQueue的數據吞吐量要大於ArrayBlockingQueue,但在線程數量很大時其性能的可預見性低於ArrayBlockingQueue.
BlockingQueue和Queue的區別:
1.BlockingQueue:支持兩個附加操做的 Queue,這兩個操做是:檢索元素時等待隊列變爲非空,以及存儲元素時等待空間變得可用。
2.BlockingQueue 不接受 null 元素。
3.BlockingQueue 能夠是限定容量的。
4.BlockingQueue 實現是線程安全的。Queue不是線程安全的。所以能夠將Blockingqueue用於用於生產者-使用者隊列。