ConcurrentLinkedQueue與LinkedBlockingQueue的對比
由於2採用讀寫鎖的形式對讀寫進行控制,可能會在鎖的獲取與釋放上損失一定的效能。所以當有多個消費者時多用1。
而對於2,我們在其原始碼中可以看到,獲取隊首元素有take與poll方法,這兩者的最本質區別在於,當佇列為空時take執行緒會被阻塞,呼叫wait()方法釋放其所佔有的資源。當有新元素入隊時會被notify,但是對於poll,若佇列為空,會直接返回null,所以在多執行緒中,如果消費者速度大於生產者速度,會導致佇列經常為空,這時如果不在poll的返回值為空時進行必要的處理,會導致執行緒空轉,最壞情況下會導致cpu使用率飆升。我們可以採用鎖的形式線上程內部主動wait(),而在入隊時notify或者notifyall來參照take方法,防止大量的執行緒空轉。
對於1,由於其內部沒有類似於2的take方法,除了poll與peek之外,沒有提供別的獲取元素的方法,這兩者的區別在於是否會彈出隊首元素。但是這時如果消費速度大於生產速度,同樣會產生上面的問題,這時我們就必須採用顯式的方法加鎖呼叫wait()方法,防止cpu等資源的浪費。提高併發效能。
通過入隊、出隊一百萬次進行效能比較
1、生產者10個,消費者100個(進隊效率,後續會給出出隊效率)
take | poll+wait() | poll | |
---|---|---|---|
LinkedBlockingQueue | 3250 / 20% | 1900 / 28% | 至少幾分鐘 / 100% |
ConcurrentLinkedQueue | -- | 1890 / 24% | 7400 / 75% |
對比以上資料可以得出,
1、對於LinkedBlockingQueue,take方法雖然在內部實現了加鎖wait(),但是由於其他的開銷,導致效能相比於poll+wait()有所下降。但是如果採用poll方法,那麼由於大量的執行緒存在空轉的情況,導致爭用處理機,導致效能急劇下降。
2、對於ConcurrentLinkedQueue,由於內部採用CAS保證併發安全,在採用poll+wait()時相比前者有所提升,但是不是很明顯,但是對於poll方式,由於去除了鎖的開銷,同時雖然相比於其自身的poll+wait()方式效能下降不少,但是相對於LinkedBlockingQueue,效能提升相當明顯。