2017-08-16 55 views
2

我正在編寫一個Web應用程序,因此併發性問題。我需要使用每10分鐘過期的令牌調用API,因此在每次調用API之前,我都需要檢查新的令牌。是否在兩個相同的條件語句之間鎖定好的模式?

我對併發設計沒有任何經驗,所以這就是我正在做的事情,我需要有人來澄清我是否做得很好。它是反模式嗎?注意:類本身是單例。

private object tokenLock = new object(); 
    private void RequestApi() 
    { 
     if (DateTime.UtcNow >= this.TokenExpireTime) 
     { 
      lock (this.tokenLock) 
      { 
       if (DateTime.UtcNow >= this.TokenExpireTime) 
       { 
        // Request new Token 
        // Update new Token Expiration Time 
       } 
      } 
     } 

     // Request API 
    } 

爲了避免重複的代碼,我可以改寫成一個屬性(邏輯仍然是相同的):

private void RequestApi() 
    { 
     if (this.NeedNewToken) 
     { 
      lock (this.tokenLock) 
      { 
       if (this.NeedNewToken) 
       { 
        // Request new Token 
        // Update new Token Expiration Time 
       } 
      } 
     } 

     // Request API 
    } 

    private bool NeedNewToken => DateTime.UtcNow >= this.TokenExpireTime; 
+2

這更多屬於CodeReview而不是StackOverflow – derape

+0

實際上,我想我甚至會創建一個函數,我們稱它爲「EnsureToken()」,它封裝了該模式。雖然模式本身是不好的做法是另一個問題。恐怕這將被視爲「主要是有見地的」。 – Fildor

+0

您正確地使用兩者之間的鎖進行驗證。使用財產或不是基於意見。但請確保您也將寫入過程鎖定爲「TokenExpireTime」。否則,在寫入時可能會從'TokenExpireTime'讀取結果。結果在那種情況下是未知的。 –

回答

2

你應該擺脫外,不同步的比較。

首先,您使用的圖案被稱爲"double-checked locking"。它通常只用於爭用程度較高且需要鎖定的可能性較低的情況,以證明代碼的尷尬。

單就這一點而言,在這種情況下不太可能需要使用它。雖然,我承認在這方面,這個問題是一個意見問題。

但更重要的是,雙重檢查的鎖定取決於您能夠安全地進行條件測試,而無需同步,但在此情況並非如此。 DateTime值不是原語,因此無法在沒有同步的情況下安全地訪問。否則,可能會產生「撕裂」的值,即部分寫入的值,既不是舊值也不是新值。

在這方面,問題是不是的意見。代碼只是不正確的,需要修復。只要拿起鎖,然後在鎖內做任何你需要做的事情。不要試圖用一個不同步的比較來簡化。這種情況並不安全。

相關問題