關於BlockingQueue和TransferQueue的異同。
- TransferQueue繼承了BlockingQueue並擴展了一些新方法。BlockingQueue是Java 5中加入的接口,它是指這樣的一個隊列:當生產者向隊列添加元素但隊列已滿時,生產者會被阻塞;當消費者從隊列移除元素但隊列爲空時,消費者會被阻塞。
- TransferQueue則更進一步,生產者會一直阻塞直到所添加到隊列的元素被某一個消費者所消費(不只僅是添加到隊列裏就完事),新添加的transfer方法用來實現這種約束。顧名思義,阻塞就是發生在元素從一個線程transfer到另外一個線程的過程當中,它有效地實現了元素在線程之間的傳遞(以創建Java內存模型中的happens-before關係的方式)。
- TransferQueue還包括了其餘的一些方法:兩個tryTransfer方法,一個是非阻塞的,另外一個帶有timeout參數設置超時時間的。還有兩個輔助方法hasWaitingConsumer()和getWaitingConsumerCount()。
- TransferQueue相比SynchronousQueue用處更廣、更好用,由於你能夠決定是使用BlockingQueue的方法(例如put方法)仍是確保一次傳遞完成(即transfer方法)。在隊列中已有元素的狀況下,調用transfer方法,能夠確保隊列中被傳遞元素以前的全部元素都能被處理。Doug Lea說從功能角度來說,LinkedTransferQueue其實是ConcurrentLinkedQueue、SynchronousQueue(公平模式)和LinkedBlockingQueue的超集。並且LinkedTransferQueue更好用,由於它不只僅綜合了這幾個類的功能,同時也提供了更高效的實現。
使用場景:當咱們不想生產者過分生產消息時,TransferQueue可能很是有用,可避免發生OutOfMemory錯誤。在這樣的設計中,消費者的消費能力將決定生產者產生消息的速度。java
https://segmentfault.com/a/1190000011266361node
http://blog.csdn.net/yjian2008/article/details/16951811算法
1.8中ConcurrentHashMap的實現原理。
- ConcurrentHashMap在jdk1.8中主要作了2方面的改進:改進一是取消segments字段,直接採用transient volatile HashEntry[] table保存數據,採用table數組元素做爲鎖,從而實現了對每一行數據進行加鎖,進一步減小併發衝突的機率;改進二是將原先table數組+單向鏈表的數據結構,變動爲table數組+單向鏈表+紅黑樹的結構,對於hash表來講,最核心的能力在於將key hash以後能均勻的分佈在數組中,若是hash以後散列的很均勻,那麼table數組中的每一個隊列長度主要爲0或者1。但實際狀況並不是老是如此理想,雖然ConcurrentHashMap類默認的加載因子爲0.75,可是在數據量過大或者運氣不佳的狀況下,仍是會存在一些隊列長度過長的狀況,若是仍是採用單向列表方式,那麼查詢某個節點的時間複雜度爲O(n);所以,對於個數超過8(默認值)的列表,jdk1.8中採用了紅黑樹的結構,那麼查詢的時間複雜度能夠下降到O(logN),能夠改進性能。
- TreeNode類:樹節點類,另一個核心的數據結構。當鏈表長度過長的時候,會轉換爲TreeNode。可是與HashMap不相同的是,它並非直接轉換爲紅黑樹,而是把這些結點包裝成TreeNode放在TreeBin對象中,由TreeBin完成對紅黑樹的包裝。並且TreeNode在ConcurrentHashMap繼承自Node類,而並不是HashMap中的集成自LinkedHashMap.Entry。
- 二叉查找樹,也稱有序二叉樹(ordered binary tree),是指一棵空樹或者具備下列性質的二叉樹:
1.若任意節點的左子樹不空,則左子樹上全部結點的值均小於它的根結點的值;
2.若任意節點的右子樹不空,則右子樹上全部結點的值均大於它的根結點的值;
3.任意節點的左、右子樹也分別爲二叉查找樹。
4.沒有鍵值相等的節點(no duplicate nodes)。
- 紅黑樹雖然本質上是一棵二叉查找樹,但它在二叉查找樹的基礎上增長了着色和相關的性質使得紅黑樹相對平衡,從而保證了紅黑樹的查找、插入、刪除的時間複雜度最壞爲O(log n)。但它是如何保證一棵n個結點的紅黑樹的高度始終保持在logn的呢?這就引出了紅黑樹的5個性質:
1.每一個結點要麼是紅的要麼是黑的。
2.根結點是黑的。
3.每一個葉結點(葉結點即指樹尾端NIL指針或NULL結點)都是黑的。
4.若是一個結點是紅的,那麼它的兩個兒子都是黑的。
5.對於任意結點而言,其到葉結點樹尾端NIL指針的每條路徑都包含相同數目的黑結點。
在擴充HashMap的時候,不須要像JDK1.7的實現那樣從新計算hash,只須要看看原來的hash值新增的那個bit是1仍是0就行了,是0的話索引沒變,是1的話索引變成「原索引+oldCap」。這個設計確實很是的巧妙,既省去了從新計算hash值的時間,並且同時,因爲新增的1bit是0仍是1能夠認爲是隨機的,所以resize的過程,均勻的把以前的衝突的節點分散到新的bucket了。segmentfault
Java8對讀寫鎖的改進:StampedLock
讀不阻塞寫的實現思路:數組
在讀的時候若是發生了寫,則應當重讀而不是在讀的時候直接阻塞寫!服務器
使用StampedLock就能夠實現一種無障礙操做,即讀寫之間不會阻塞對方,可是寫和寫之間仍是阻塞的!數據結構
http://blog.csdn.net/sunfeizhi/article/details/52135136多線程
什麼是一致性哈希?
- 環形Hash空間:按照經常使用的hash算法來將對應的key哈希到一個具備2^32次方個桶的空間中,即0~(2^32)-1的數字空間中。如今咱們能夠將這些數字頭尾相連,想象成一個閉合的環形;
- 把數據經過必定的hash算法處理後映射到環上;
- 將機器經過hash算法映射到環上(通常狀況下對機器的hash計算是採用機器的IP或者機器惟一的別名做爲輸入值),而後以順時針的方向計算,將全部對象存儲到離本身最近的機器中;
- 機器的刪除與添加:普通hash求餘算法最爲不妥的地方就是在有機器的添加或者刪除以後會照成大量的對象存儲位置失效,這樣就大大的不知足單調性了。經過對節點的添加和刪除的分析,一致性哈希算法在保持了單調性的同時,仍是數據的遷移達到了最小,這樣的算法對分佈式集羣來講是很是合適的,避免了大量數據遷移,減少了服務器的的壓力。
- 平衡性:在一致性哈希算法中,爲了儘量的知足平衡性,其引入了虛擬節點。它其實是節點在hash空間的複製品,一實際個節點對應了若干個「虛擬節點」,這個對應個數也成爲「複製個數」,「虛擬節點」在hash空間中以hash值排列。
AtomicLong、LongAdder和LongAccumulator的實現有何不一樣?
- AtomicLong是Java 5引入的基於CAS的無鎖的操做長整形值的工具類;
- LongAdder是Java 8提供的累加器,基於Striped64實現。它經常使用於狀態採集、統計等場景。AtomicLong也能夠用於這種場景,但在線程競爭激烈的狀況下,LongAdder要比AtomicLong擁有更高的吞吐量,但會耗費更多的內存空間。
-
LongAdder用多個cell的值的sum來表示一個long型數據。相似鎖分段的思想,在有併發衝突的場景下,每一個線程更新一個cell,經過不一樣線程修改各自的cell,來下降併發競爭。當每一個cell的更新還有衝突時,進行cell擴容,來進一步下降競爭。cell的個數不是無限大的,和cpu的核數有關。app
想要獲取LongAdder表示的數據時,經過sum來計算base和每一個cell的值的和。
-
LongAdder給了咱們一個很是容易想到的解決方案:減小併發,將單一value的更新壓力分擔到多個value中去,下降單個value的 「熱度」,分段更新!惟一會制約AtomicLong高效的緣由是高併發,高併發意味着CAS的失敗概率更高, 重試次數更多,越多線程重試,CAS失敗概率又越高,變成惡性循環,AtomicLong效率下降。Cell數組中的每一項就是一個段,當咱們須要獲得值時,將全部cell中的數據和base相加就能夠了。
- Striped64的設計核心思路就是經過內部的分散計算來避免競爭(好比多線程CAS操做時的競爭)。Striped64內部包含一個基礎值和一個單元哈希表。沒有競爭的狀況下,要累加的數會累加到這個基礎值上;若是有競爭的話,會將要累加的數累加到單元哈希表中的某個單元裏面。因此整個Striped64的值包括基礎值和單元哈希表中全部單元的值的總和。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/** * 存放Cell的hash表,大小爲2的冪。 */ transient volatile Cell[] cells; /** * 基礎值,沒有競爭時會使用(更新)這個值,同時作爲初始化競爭失敗的回退方案。 * 原子更新。 */ transient volatile long base; /** * 自旋鎖,經過CAS操做加鎖,用於保護建立或者擴展Cell表。 */ transient volatile int cellsBusy; |
- LongAccumulator和LongAdder相似,也基於Striped64實現。但要比LongAdder更加靈活(要傳入一個函數接口),LongAdder至關因而LongAccumulator的一種特例。
http://ginobefunny.com/post/java_concurrent_interview_questions/