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()。有人能详细说明一下我的具体情况吗?

C#使用lock()语句和缓存数据

lock只有在所有要同步的位置应用锁时才有用。因此每次访问Names时,都需要访问lock。目前,这只会停止两个线程同时交换Names,坦率地说,这在这里不是问题,因为引用交换无论如何都是原子交换。

另一个问题;推测Namesnull开始?你不能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内联,所以它不是惩罚。

不,这是不正确的,因为任何人都可以直接使用Names属性。
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()的调用方也执行相同的测试。