c# - 两个相同条件语句之间的锁定是好的模式吗?

标签 c# design-patterns concurrency race-condition

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

相关文章:

concurrency - 您可以使用被同步为锁的对象吗?

C# RestSharp 阻止 302 上的请求重定向

C# WinForms 读取 XML 文件 - 仅特定节点

design-patterns - 访问者模式和编译器代码生成,如何获取子属性?

php - 设计问题 : Which is Better practice?(第 2 部分)

python - 传递已解析的参数并不有趣

java - 哪个并发列表适合多个作者一个读者?

c# - 在所有者对象初始化器中初始化 get-only 属性

c# - 这两种声明 self 绑定(bind)的方式有什么区别?

java - 原子变量是否保证内存可见性?