此静态字典字段线程是否安全
本文关键字:是否 安全 线程 字段 静态 字典 | 更新日期: 2023-09-27 17:57:17
这是 Asp.net MVC Web Project。
我每 30 秒准备一次"用户树"。(刷新用户方法)所以集合操作是原子的。获取操作是多线程的。
这种方法线程安全吗?
public static class InternalCache
{
private static Dictionary<long, UserModel> _Users;
public static RefreshUsers(){
//.............
// var res=.......
_Users= res;
}
public static UserModel GetUser(long id){
return _Users[id];
}
}
尽管静态变量的设置为原子变量,但您仍然面临编译器优化和指令重新排序可能导致某些线程看到_Users
的过时值的风险。
要删除它,您需要在访问静态变量时使用lock
或使用Interlocked
函数读取/写入变量:
public static class InternalCache
{
private static Dictionary<long, UserModel> _Users;
public static RefreshUsers()
{
Interlocked.Exchange(ref _Users, res);
}
public static UserModel GetUser(long id)
{
// Read the variable, ensuring we always see the latest value
var users = Interlocked.CompareExchange(ref _Users, null, null);
return users[id];
}
}
如果你可以确保一次只有一个线程调用你的RefreshUsers
函数,那么是的,你的代码应该是线程安全的。
否则,您必须使函数线程安全:
为了使函数线程安全,您需要一个要锁定的对象:
private static object _lockObj = new Object();
然后在写入_Users
时以及获取该对象时锁定该对象:
public static class InternalCache
{
private static Dictionary<long, UserModel> _Users;
private static object _lockObj = new Object();
public static RefreshUsers(){
lock (_lockObj)
{
//.............
// var res=.......
_Users= res;
}
}
public static UserModel GetUser(long id){
return _Users[id];
}
}
锁确保锁块内的所有内容一次只能由一个线程访问,因为线程在到达该对象lock(...)
行后立即锁定该对象。因此,当下一个线程到达此行时,他无法锁定该对象,而是等到另一个线程释放了锁。