我正在编写一个Web应用程序,因此关注并发性。我需要使用每 10 分钟就会过期的 token 来调用 API,因此在每次 API 调用之前,我需要检查是否有新 token 。
我没有任何并发设计的经验,所以这就是我正在做的事情,我需要有人来澄清我是否做得很好。它是反模式吗?注意:类本身是单例的。
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;
最佳答案
您应该摆脱外部的、不同步的比较。
首先,您使用的模式名为 "double-checked locking" 。它通常仅在存在高度争用且需要获取锁定的可能性较低的情况下使用,这证明了代码的尴尬。
仅凭这一点,在这种情况下您不太可能真正需要使用它。不过,我承认,在这方面,这个问题只是见仁见智的问题。
但更重要的是,双重检查锁定取决于您是否能够在不同步的情况下安全地进行条件测试本身,但这里的情况并非如此。 DateTime
值不是基元,因此在没有同步的情况下无法安全访问。否则,您将面临获得“撕裂”值的风险,即部分写入的值,因此既不是旧值也不是新值。
在这方面,这个问题不是一个意见问题。该代码根本不正确,需要修复。只需拿着锁,然后在锁内做任何你需要做的事情。不要试图通过不同步的比较走捷径。在这种情况下并不安全。
关于c# - 两个相同条件语句之间的锁定是好的模式吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45706189/