锁定两个相同的条件语句之间的良好模式?

时间:2017-08-16 06:08:04

标签: c# design-patterns concurrency race-condition

我正在编写一个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;

1 个答案:

答案 0 :(得分:2)

你应该摆脱外部的,不同步的比较。

首先,您使用的模式称为"double-checked locking"。它通常仅在存在高级别争用且需要锁定的可能性较低的情况下使用,从而证明代码的尴尬。

仅在此基础上,在这种情况下你不太可能真的需要使用它。虽然,我承认在这方面,问题是一个意见问题。

但更重要的是,双重检查锁定取决于您能够在没有同步的情况下安全地进行条件测试,这不是这里的情况。 DateTime值不是原始值,因此无法在没有同步的情况下安全访问。否则,您将面临获得“撕裂”值的风险,即部分写入的值,因此既不是旧值也不是新值。

在这方面,问题是是一个意见问题。代码很简单,需要修复。只需拿锁,在锁内做任何你需要做的事情。不要尝试使用不同步的比较进行快捷方式。在这种情况下,这不安全。