C#使用lock()语句和缓存数据
本文关键字:缓存 数据 语句 使用 lock | 更新日期: 2023-09-27 18:24:53
我的应用程序中有许多静态List,它们用于存储数据库中的数据,并在查找信息时使用:
public static IList<string> Names;
我还有一些方法可以从数据库中刷新这些数据:
public static void GetNames()
{
SQLEngine sql = new SQLEngine(ConnectionString);
lock (Names)
{
Names = sql.GetDataTable("SELECT * FROM Names").ToList<string>();
}
}
起初我没有锁定(),但我偶尔会注意到,请求线程在列表中找不到信息。现在,我假设,如果请求线程试图访问Names列表,那么它在完全更新之前是无法访问的。
这是lock()语句的正确方法和用法吗?
顺便说一句,我在MSDN上注意到,不应该对公共变量使用lock()。有人能详细说明一下我的具体情况吗?
lock
只有在所有要同步的位置也应用锁时才有用。因此每次访问Names
时,都需要访问lock
。目前,这只会停止两个线程同时交换Names
,坦率地说,这在这里不是问题,因为引用交换无论如何都是原子交换。
另一个问题;推测Names
从null
开始?你不能lock
也不能null
。同样,您不应该锁定可能更改引用的内容。如果你想同步,一种常见的方法是:
// do not use for your scenario - see below
private static readonly object lockObj = new object();
然后是CCD_ 9而不是您的数据。
关于不锁定外部可见的事物;对这是因为其他一些代码可能会随机选择对其执行lock
,这可能会导致意外的阻塞,并且很可能导致死锁。
另一个大风险是,您的一些代码会获得名称,然后进行排序/添加/删除/清除等操作——任何会使数据发生变异的操作。就我个人而言,我会在这里使用只读列表。事实上,对于只读列表,您所拥有的只是一个引用交换;因为这是原子的,所以不需要任何锁定:
public static IList<string> Names { get; private set; }
public static void UpdateNames() {
List<string> tmp = SomeSqlQuery();
Names = tmp.AsReadOnly();
}
最后:公共字段非常非常很少是个好主意。因此产生了上述性质。这将由JIT内联,所以它不是惩罚。
public class SomeClass
{
private List<string> _names;
private object _namesLock = new object();
public IEnumerable<string> Names
{
get
{
if (_names == null)
{
lock (_namesLock )
{
if (_names == null)
_names = GetNames();
}
}
return _names;
}
}
public void UpdateNames()
{
lock (_namesLock)
GetNames();
}
private void GetNames()
{
SQLEngine sql = new SQLEngine(ConnectionString);
_names = sql.GetDataTable("SELECT * FROM Names").ToList<string>();
}
}
尽量避免使用静态方法。至少使用一个singleton。
检查、锁定、检查比锁定、检查快,因为写入只会发生一次。
在使用时指定属性称为延迟加载。
_namesLock
是必需的,因为您不能锁定null。
从您显示的oode中,第一次调用GetNames()时,Names属性为null。我不知道对空对象的锁定会做什么。我会添加一个变量来锁定。
static object namesLock = new object();
然后在GetNames()中
lock (namesLock)
{
if (Names == null)
Names = ...;
}
我们在锁内进行if测试()以停止比赛条件。我假设GetNames()的调用方也执行相同的测试。