獨佔式同步狀態獲取與釋放

2021-08-26 11:56:02 字數 2214 閱讀 5300

通過呼叫同步器的acquire(int arg)方法可以獲取同步狀態,該方法對中斷不敏感,也就是由於執行緒獲取同步狀態失敗後進入同步佇列中,後續對執行緒進行中斷操作時,執行緒不會從同步佇列中移出。該方法**清單如下。

public final void acquire (int arg)
分析節點的構造以及加入到同步佇列,**如下

private node addwaiter(node mode)

}enq(node);

return node;

}public node enq(final node node)else }}

}

上述**通過使用compareandsettail(node expect,node update)方法來確保節點能夠被執行緒安全新增。試想下:若使用乙個普通的linkedlist來維護節點之間的關係,那麼當乙個執行緒獲取了同步狀態,而其他執行緒由於呼叫tryacquire(int arg)方法獲取同步狀態失敗而併發的新增到linkedlist時,而linkedlist將難以保證node的正確新增,最終的結果可能是節點的數量有偏差,而且順序也是混亂的。

在enq(final node node)方法中,同步器通過死迴圈來保證節點的正確新增,在"死迴圈"中只有通過cas將節點設定成尾節點後,當前執行緒才能從該方法返回。否則,當前執行緒不斷的嘗試設定。如此看出,enq(final node node)方法將併發新增節點的請求通過cas變得「序列化」了。

當節點進入同步佇列後,進入了乙個自旋的過程,每個節點(或者說每個執行緒)都在自省的觀察,當條件滿足,獲取到了同步狀態,就可以從這個自旋過程中退出,否則依舊留在這個過程中(並會阻塞節點的執行緒)。**如下;

final boolean acquirequeued(final node node,int arg)

if (shouldparkafte***iledacquire(p,node) && parkandcheckinterrupt())

interrupted=true;

}}finally

}

在acquirequeued(final node node ,int arg)方法中,當前執行緒在「死迴圈」中嘗試獲取同步狀態,而只有前驅節點是頭節點才能夠獲取同步狀態。

原因之一,頭節點是成功獲取到同步狀態的節點,而頭節點的執行緒釋放了同步狀態後,將會喚醒其後繼承點,後繼節點的執行緒被喚醒後需要檢查自己的前驅節點是否是頭節點。

原因之二,維護同步佇列的fifo原則,該方法中,節點自旋獲取同步狀態的行為如下圖所示。

在上圖中,由於非首節點執行緒前驅節點出隊或者被中斷而從等待狀態返回,隨後檢查自己的前驅是否是頭節點,若是則獲取同步狀態。可以看到節點和節點之間在迴圈檢查的過程中基本不相互通訊,而是簡單的判斷自己的前驅是否為頭節點,這樣使得節點的釋放規則符合fifo,並且也便於對過早通知的處理(過早通知是指前驅節點不是頭節點的執行緒由於中斷而被喚醒)。

獨佔式同步狀態獲取流程,也是acquire(int arg)方法呼叫流程如下

在上圖中,前驅節點為頭節點且能夠獲取同步狀態的判斷條件和執行緒進入等待狀態是獲取同步狀態的自旋過程。當同步狀態獲取成功後,當前執行緒從acquire(int arg)方法返回。若對於鎖這種鎖併發元件而言,代表著當前執行緒獲取了鎖。

當前執行緒獲取同步狀態並執行了相應邏輯後,就需要釋放同步狀態,使得後繼節點能夠繼續獲取同步狀態。通過呼叫同步器的release(int arg)方法可以釋放同步狀態,該方法釋放後,會喚醒其後繼節點(進而使後繼節點重新嘗試獲取同步狀態)。其**如下:

public  final boolean release(int arg)

return false;

}

該方法執行時,會喚醒頭節點的後繼節點執行緒,unparksuccessor(node node)方法使用looksupport來喚醒處於等待狀態的執行緒。

總結:在獲取同步狀態時,同步器維護乙個同步佇列,獲取狀態失敗的執行緒都會加入到佇列中進行自旋;移出佇列(或停止自旋)的條件是前驅節點為頭節點且成功獲取了同步狀態。在釋放同步狀態是,同步器呼叫tryrelease(int arg)釋放同步狀態,然後喚醒頭節點的後繼節點。

佇列同步器 獨佔式同步狀態獲取與釋放

佇列同步器的實現依賴內部的同步佇列來完成同步狀態的管理。它是乙個fifo的雙向佇列,當執行緒獲取同步狀態失敗時,同步器會將當前執行緒和等待狀態等資訊包裝成乙個節點並將其加入同步佇列,同時會阻塞當前執行緒。當同步狀態釋放時,會把頭節點中的執行緒喚醒,使其再次嘗試獲取同步狀態。node靜態內部類的原始碼...

遊戲中幀同步與狀態同步

幀同步 什麼是幀同步 幀同步常被rts 即時戰略 遊戲常採用。在遊戲中同步的是玩家的操作指令,操作指令包含當前的幀索引。一般的流程是客戶端上傳操作到伺服器,伺服器收到後並不計算遊戲行為,而是 到所有客戶端。這裡最重要的概念就是 相同的輸入 相同的時機 相同的輸出。實現幀同步的流程一般是 同步隨機數種...

AQS(獲取資源 獨佔模式)2) 佇列同步器

1.獲取資源 獨佔模式 acquire int 首先講解獨佔模式 exclusive 下的獲取 釋放資源過程,其入口方法為 public final void acquire int arg tryacquire arg 為執行緒獲取資源的方法函式,在aqs中定義如下 protected boole...