了解 List<T> 的线程安全

Understanding the thread safety of a List<T>

  1. 我想了解为什么它会打印第 0 项、第 0 项和第 1 项
  2. 在调试时它打印项目 0、项目 0、项目 1、项目 1

上面 2 个结果中的项目符号有意义。谁能帮我理解为什么它在 1 中打印子弹?

摘自 C# 9.0 简述

class ThreadSafe
{
    static List<string> _list = new List<string>();

    public static void AddItem()
    {
        // lock the list
        lock (_list)
        {
            _list.Add("Item " + _list.Count);
        }
        // Rather than locking for the duration; copy to an array
        string[] items;
        lock (_list)
        {
            items = _list.ToArray();
        }
        foreach (string s in items)
        {
            Console.WriteLine(s);
        }
     }
     static void Main(string[] args)
     {
       new Thread(ThreadSafe.AddItem).Start();
       new Thread(ThreadSafe.AddItem).Start();
     }
}

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement

While a lock is held, the thread that holds the lock can again acquire and release the lock. Any other thread is blocked from acquiring the lock and waits until the lock is released.

这确实取决于环境,但直接的答案如下。

  1. 线程 1 将锁定列表。
  2. 线程 2 将尝试访问但无法访问,因此它将等待
  3. 线程 1 将添加到列表中
  4. 线程 2 仍在等待
  5. 线程 1 将释放锁
  6. 线程 2 将锁定列表
  7. 线程 1 将尝试锁定列表,但它已经被锁定,因此它将等待
  8. 等等

这实际上取决于线程何时真正开始计算。但这将是对您所看到的输出的最合乎逻辑的答案。 运行 它在不同的环境(CPU 等)上可能会导致不同的输出。