是列表<;T>;如果只是更改值,则线程安全

本文关键字:安全 线程 如果 lt 列表 gt | 更新日期: 2023-09-27 18:23:38

如果我有一个包含100个项目的列表,以及4个线程,每个线程更改25个项目,这样它们就不会更改彼此的项目,那么这个列表会是"线程安全的"吗?也就是说,它会按预期工作吗?

举个例子,你有一个1000只猫的数组,它们的"name"属性为空,因为它们还没有被命名。您希望遍历并命名所有这些,但希望它是多线程的。因此,您创建了10个线程,并告诉每个线程只执行0-99、100-199等操作,然后将它们设置为关闭状态

这会起作用,因为您只是从列表中读取。你不写。

是列表<;T>;如果只是更改值,则线程安全

正如其他人已经指出的,读取行为本质上是线程安全的。只有当某些线程想要写入和/或其他线程想要从资源中读取时,并发才成为问题。

话虽如此,我可以补充一点,如果您为此目的使用集合,则可以考虑使用显式只读集合(或简单地使用IEnumerable)。NET现在提供了这些开箱即用的只读集合。这样可以更明确地表明,您只是在阅读该集合。

顺便说一句:我不知道你的需求的上下文,也许你只是过于简化了这里的问题,但对内存中集合的串行访问速度非常快,所以只有在以下情况下,从集合中读取多个线程才是有根据的:

  • 您不是从内存读取,而是从磁盘读取(I/O很慢)
  • 您正在执行的操作对象的操作很慢(就像毫秒或更大的数量级,而不是简单的属性修改)

如果您没有对列表本身进行中间化(添加或删除项目),并且您可以确保4个线程只处理它们自己的对象,那么从线程同步的角度来看,就没问题了

您可以使用并行linq功能,而不是一些自制的线程:

namespace CSharp
{
  using System;
  using System.Collections.Generic;
  using System.Linq;
  class Cat
  {
    public string Name { get; set; }
  }
  class Program
  {
    private static void Main()
    {
      var cats = new List<Cat>();
      for (int i = 0; i < 100; ++i)
      {
        cats.Add(new Cat());
      }
      cats.AsParallel().ForAll(cat => cat.Name = "Carlo");
      foreach (var cat in cats)
      {
        Console.WriteLine(cat.Name);
      }
      Console.ReadLine();
    }
  }
}