2016-12-27 80 views
4

我一直在閱讀在Java中source code of PriorityBlockingQueue,我想知道:什麼是PriorityBlockingQueue中的鎖定/解鎖推理?

  1. 爲什麼是tryGrow()方法釋放報價期間獲得的鎖()方法,只是做它的事非阻塞,然後在準備好替換隊列中的內容時再次阻塞?我的意思是,它可能只是保持它的鎖...
  2. 這是如何工作的?增加包含數組副本的隊列不會對併發添加造成不當行爲,噹噹前添加增加隊列的大小時,可以完全增加額外的增量?

回答

3

因爲內存分配可能比較慢,可以在陣列解鎖時完成。

通過釋放鎖定,允許其他線程在分配(可能很大)的新陣列時繼續運行。

由於這個過程可以在沒有鎖的情況下完成,所以最好這樣做。您只應持有一個鎖定時間的最短時間,你必須。

進行了足夠的檢查以確保沒有其他線程在同一時間執行此操作。

UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset, 0, 1) 

一次只允許一個線程進入這段代碼。

注意

lock.lock(); 
if (newArray != null && queue == array) { 

這又抓起鎖,然後確認它是關於更換陣列是同一個,它抓住的副本在開始。如果它已被替換,那麼它只是放棄它剛剛創建的那個假設,其他線程已經增長了陣列。

如果它仍然是相同的,它會將舊數據複製到新的更大的數組中並將其植入現場。

至於Kamil很好解釋。

解鎖的目的只是爲了確保更快的線程會增加隊列,所以我們不會浪費時間鎖定「更好的」。

+1

我想補充一點,在我看來,通過代碼閱讀後,它只是讓其他線程競爭日益增長的數組。他們基本上不能做其他事情。如果有人去嘗試一下,我們可以肯定,另一個嘗試放置元素的元素,在釋放鎖之後,也只能嘗試一下tryGrow。解鎖的目的只是爲了確保更快的線程將增加隊列,所以我們不會浪費時間鎖定「更好的」線程。我希望這對你有意義:) –

+0

@Kamil的確,這確實很有意義。然而,我擔心的是當一個線程被釋放並且正在增長,而下一個線程試圖增長,跳過(導致最初的線程已經在增長),並且替換隊列 – Belun

+1

你看,他不這樣做這要感謝if(newArray!= null && queue == array),newArray將爲null,因爲other正在分配。他將處於鎖定和解鎖鎖定的死循環中,直到其他人嘗試增長鎖定爲止。之後,他們將放置它們的值,並且增加數組的線程將首先歸功於替換隊列之前的鎖定。基本上,如果在tryGrow中,第一個會更快,其餘的則需要等待 –