Monitor 等待缓存,...这是一个好习惯吗?

Monitor Wait for caching,... it this a good practice?

我刚刚写了一个代码,然后我发现 monitor.wait 有一些问题,迫使我在锁内进行操作,我现在想如果这是一个好方法保持线程等待,....

我不确定 thread.join 是否可以完成这项工作,因为我的应用程序中有很多线程 运行,每个线程都执行特定的工作,它们可能会在指定时间内终止...

这是我的代码:

public static class TaskManager
{
    private static readonly object UpdateLock = new object();
    private static readonly object WaitLock = new object();

    private static readonly LiaisonDb _db = new LiaisonDb();
    private static List<liaQueue> _liaQueueList = new List<liaQueue>();
    private static DateTime _lastUpdate = new DateTime();

    public static liaQueue GetTask(string sessionType)
    {
        liaQueue task;
        lock (UpdateLock)
        {
            if (_lastUpdate < DateTime.Now.AddSeconds(-5))
            {
                Thread t = new Thread(UpdateCache) {IsBackground = true};
                t.Start();
                lock (WaitLock)
                {
                    Monitor.Wait(WaitLock);
                }

                _lastUpdate = DateTime.Now;
            }
            task = _liaQueueList
                .FirstOrDefault(w => w.Stat == 0
                                     && w.Type != null
                                     || string.Equals(w.Type, sessionType));
        }
        return task;
    }

    private static void UpdateCache()
    {
        try
        {
            _liaQueueList = _db.liaQueue.Where(w => w.Stat == 0).ToList();
        }
        finally
        {
            lock (WaitLock)
            {
                Monitor.Pulse(WaitLock);
            }
        }
    }
}

如你所见,我放了两把锁,其中一把仅用于 monitor.wait,让线程等待答案...

我想我还必须 returns 在缓存刷新时为空?...

来自MSDN

If two threads are using Pulse and Wait to interact, this could result in a deadlock.

所以,没有。您的实施不是最佳实践。

在我看来,GetTask 应该在后台线程上更新缓存,然后阻塞调用线程直到缓存被更新,然后 return 第一个任务根据 select 标准。

由于调用线程会阻​​塞(等待)缓存更新,所以我一开始不太明白使用后台线程的意义。 如果目的是防止多个调用线程并行更新缓存,只需使用 lock(UpdateLock) 语句。

如果您确实想要 运行 后台线程上的缓存(并等待),请考虑改用 Task 库。但是我真的不明白它的意义。

lock (UpdateLock)
{
  if (_lastUpdate < DateTime.Now.AddSeconds(-5)) {
    Task.Run(() => {
      _liaQueueList = _db.liaQueue.Where(w => w.Stat == 0).ToList();
    }).Wait();

    _lastUpdate = DateTime.Now;
  }
}

return _liaQueueList.FirstOrDefault(w => w.Stat == 0 && w.Type != null || string.Equals(w.Type, sessionType));