此代码线程在 ASP.NET MVC 4 中安全吗?

Is this code thread safe in ASP.NET MVC 4?

根据我目前的理解,我认为这段代码不是线程安全的,但想确认一下。换句话说,我认为,虽然这极不可能,但代表不同 HTTP 请求的多个线程可能会混淆 _userName 属性.

的值
public class SomeClass
{
    private static string _userName;

    public static string UserName
    {
        get
        {
            if (string.IsNullOrEmpty(_userName))
            {
                _userName = HttpContext.Current.User.Identity.Name;
            }

            return _userName; 
        }
    }
}

它是线程安全的吗?如果不是,是否会删除空检查,并且总是直接访问 HttpContext.Current.User.Identity.Name(在静态 属性 中)是线程安全的?

public class SomeClass
{
    public static string UserName
    {
        get
        {
            return HttpContext.Current.User.Identity.Name; 
        }
    }
}

您的第二个解决方案可以正常工作。第一个 根本不是线程安全的 。在静态变量中缓存一个值会将其暴露给所有线程,如果您同时有两个或多个请求,它们很可能会读取其他请求的值。你觉得极不可能,嗯……不是,恰恰相反。

此外,如果你真的想要一个值被多个线程共享,你应该使用一些同步机制来确保正确性。在您的第一个示例中,您访问 _userName 3 次(2 次读取和 1 次写入)。您可能会遇到此变量最终具有不同值的情况,因此您应该将所有内容包含在 lock 中。只有当您明确希望在线程之间共享此信息时才会这样。

第二种方法有效,因为 HttpContext.Current 的值是从当前 execution context 中检索的(因此它取决于当前线程)。

还有一件事:在 ASP.NET 应用程序中,由于 thread agility,您不应该依赖线程本地存储,所以如果您需要缓存值,请使用 HttpContext反而。您有一个 Items 属性 允许您仅在当前请求期间存储值。但在您的特定示例中,您不必缓存此值,因为它已经从 HTTP 上下文中检索到。

你的两个例子非常不同。你是对的,你的第一个例子不是线程安全的,但更重要的问题是它不是会话安全的。访问 UserName 的第一个会话将设置用户名,所有其他会话将使用相同的名称UserName 在应用程序池被回收之前不会改变。 技术上 second 会话设置用户名是否重要,如果它在第一个请求之后发出请求?

如果要缓存每个会话的用户名,请使用 Session 属性:

Session["UserName"] = HttpContext.Current.User.Identity.Name;

第二个块线程安全的,但它returns每次调用时都是当前用户名。所以不用担心数据跨线程,更不用说会话了。