jdk7提供了7個阻塞佇列。分別是
阻塞佇列(blockingqueue)是乙個支援兩個附加操作的佇列。這兩個附加的操作是:在隊列為空時,獲取元素的執行緒會等待佇列變為非空。當佇列滿時,儲存元素的執行緒會等待佇列可用。阻塞佇列常用於生產者和消費者的場景,生產者是往佇列裡新增元素的執行緒,消費者是從佇列裡拿元素的執行緒。阻塞佇列就是生產者存放元素的容器,而消費者也只從容器裡拿元素。
阻塞佇列提供了四種處理方法:
方法\處理方式
丟擲異常
返回特殊值
一直阻塞
超時退出
插入方法
add(e)
offer(e)
put(e)
offer(e,time,unit)
移除方法
remove()
poll()
take()
poll(time,unit)
檢查方法
element()
peek()
不可用不可用
執行緒不安全的hashmap
因為多執行緒環境下,使用hashmap進行put操作會引起死迴圈,導致cpu利用率接近100%,所以在併發情況下不能使用hashmap。
效率低下的hashtable容器
concurrenthashmap的鎖分段技術
hashtable容器在競爭激烈的併發環境下表現出效率低下的原因,是因為所有訪問hashtable的執行緒都必須競爭同一把鎖,那假如容器裡有多把鎖,每一把鎖用於鎖容器其中一部分資料,那麼當多執行緒訪問容器裡不同資料段的資料時,執行緒間就不會存在鎖競爭,從而可以有效的提高併發訪問效率,這就是concurrenthashmap所使用的鎖分段技術,首先將資料分成一段一段的儲存,然後給每一段資料配一把鎖,當乙個執行緒占用鎖訪問其中乙個段資料的時候,其他段的資料也能被其他執行緒訪問。
segment的get操作實現非常簡單和高效。先經過一次再雜湊,然後使用這個雜湊值通過雜湊運算定位到segment,再通過雜湊演算法定位到元素,**如下:
1
public
v get(object key)
1
transient
volatile
int
count;
3
volatile
v value;
在定位元素的**裡我們可以發現定位hashentry和定位segment的雜湊演算法雖然一樣,都與陣列的長度減去一相與,但是相與的值不一樣,定位segment使用的是元素的hashcode通過再雜湊後得到的值的高位,而定位hashentry直接使用的是再雜湊後的值。其目的是避免兩次雜湊後的值一樣,導致元素雖然在segment裡雜湊開了,但是卻沒有在hashentry裡雜湊開。
concurrenthashmap的put操作
由於put方法裡需要對共享變數進行寫入操作,所以為了執行緒安全,在操作共享變數時必須得加鎖。put方法首先定位到segment,然後在segment裡進行插入操作。插入操作需要經歷兩個步驟,第一步判斷是否需要對segment裡的hashentry陣列進行擴容,第二步定位新增元素的位置然後放在hashentry陣列裡。
是否需要擴容。在插入元素前會先判斷segment裡的hashentry陣列是否超過容量(threshold),如果超過閥值,陣列進行擴容。值得一提的是,segment的擴容判斷比hashmap更恰當,因為hashmap是在插入元素後判斷元素是否已經到達容量的,如果到達了就進行擴容,但是很有可能擴容之後沒有新元素插入,這時hashmap就進行了一次無效的擴容。
如何擴容。擴容的時候首先會建立乙個兩倍於原容量的陣列,然後將原陣列裡的元素進行再hash後插入到新的陣列裡。為了高效concurrenthashmap不會對整個容器進行擴容,而只對某個segment進行擴容。
非常重要的git
什麼是git linux出現之後,很快成為了最火的伺服器系統,因為其是開源的,所有有非常多的人對其進行開發,以至於出現了各種不同的版本。人們把自己寫的 發給linus linu創始人 由其手動的拼接這些 手動拼接了11年之後,linus用了兩周的時間寫出了git。git是linus為linux寫的分...
NIO中幾個非常重要的技術點
這些都是在實踐中踩過雷的,今天某應用再次踩雷,把遇到的幾個雷都收集一下,給後來者參考。1.即使是accept事件,沒有真正的read和write,channel也要關閉,否則unix domain socket會被洩漏 windows更可怕 因為nio的每個 channel上都有兩個fd用來監聽事件...
NIO中幾個非常重要的技術點
這些都是在實踐中踩過雷的,今天某應用再次踩雷,把遇到的幾個雷都收集一下,給後來者參考。1.即使是accept事件,沒有真正的read和write,channel也要關閉,否則unix domain socket會被洩漏 windows更可怕 因為nio的每個 channel上都有兩個fd用來監聽事件...