根据我目前的理解,我认为这段代码不是线程安全的,但想确认一下。换句话说,我认为,尽管极不可能,代表不同 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
的第一个会话将设置用户名,并且 所有其他会话将使用相同的名称! UserName
在应用程序池被回收之前不会改变。如果第二个会话在第一个会话之后不久发出请求,那么从技术上来说第二个会话设置用户名是否重要?
如果您想缓存每个会话的用户名,请使用
Session
属性:
Session["UserName"] = HttpContext.Current.User.Identity.Name;
第二个块是线程安全的,但它每次调用时都会返回当前用户名。因此,不必担心数据跨线程交叉,更不用说会话了。
根本不是线程安全的。在静态变量中缓存一个值会将其公开给所有线程,如果您有两个或多个同时请求,它们很可能会读取其他请求的值。你认为这极不可能,嗯...事实并非如此,恰恰相反。
此外,如果你确实希望一个值在多个线程之间共享,你应该使用一些同步机制来确保正确性。在第一个示例中,您访问_userName
3 次(2 次读取和 1 次写入)。您可能会遇到该变量最终得到不同值的情况,因此您应该将所有内容都包含在
lock
中。仅当您明确希望在线程之间共享此信息时才有效。第二种方法有效,因为
HttpContext.Current
的值是从当前执行上下文 检索的(因此它依赖于当前线程)。 还有一件事:在 ASP.NET 应用程序中,由于
线程敏捷性,您不应该依赖线程本地存储,因此如果您需要缓存值,请使用 HttpContext
代替。您有一个
Items
属性,可让您仅在当前请求的持续时间内存储值。但在您的特定示例中,您不必缓存该值,因为它已经从 HTTP 上下文中检索。
您的第二个解决方案效果很好。第一个根本不是线程安全的。在静态变量中缓存一个值会将其公开给所有线程,如果您有两个或多个同时请求,它们很可能会读取其他请求的值。你认为这极不可能,嗯...事实并非如此,恰恰相反。