给定一个通过 DI 注入的单例类,当多个线程调用单例方法时会发生什么

问题描述 投票:0回答:2

我有一个非常基本的问题: 假设我有以下注册为单例的类和一个方法。当

Create()
被多个线程命中时会发生什么?所有线程是否同时访问此方法?如果 10 个线程调用此方法,一旦方法范围结束,是否会创建 10 个
numbers
变量并释放掉?

由于此类没有任何类级属性,我认为它是线程安全的?

// registration
builder.Services.AddSingleton<ISingleton, SingletonTest>();

 public interface ISingleton
 {
     int Create(int number);
 }
 public class SingletonTest : ISingleton
 {
     public int Create(int number)
     {
         List<int> numbers = new List<int>();

         numbers.Add(number);
         return numbers.Count;
     }
 }
c# .net multithreading singleton
2个回答
0
投票

所有线程是否同时访问此方法?

是的,没有额外的同步技术。 Singleton 就像创建静态成员并从多个线程访问它。

public static readonly ISingleton Instance = new SingletonTest();

如果 10 个线程调用此方法,一旦方法范围结束,是否会创建 10 个数字变量并释放掉?

是的,将创建 10 个

numbers
,但离开此方法后不会释放。释放是由运行时线程完成的,该线程执行垃圾收集器,释放未引用的已分配内存。

由于此类没有任何类级属性,我认为它是线程安全的?

是的,它是线程安全的。如果你有属性,但不可变,初始化一次,例如在构造函数中,它也将是线程安全的。


0
投票

注册为 Singleton 的类与直接控制

Create
方法没有任何关系。通过将类注册为单例,您得到的唯一承诺是,无论有多少线程需要该依赖项,也无论是否同时需要它,都只会获得
SingletonTest
的单个(吨)实例已创建。

一旦创建了该实例,它就会传递给任何需要它的人,然后他们就可以用它做任何他们想做的事情。如果它被编写为线程安全的,那么多个线程同时使用它就没有问题 - 如果不是,那么你就会遇到一些麻烦,并且 Singleton 状态不会有任何帮助。

在您的示例中,具体而言,

Create
方法非常不是线程安全。为什么?好吧,
List
并不意味着是线程安全的,并且您允许多个线程同时访问它,这意味着事情可能会中断。您可以将列表切换为
ConcurrentBag
,这将解决您的问题,因为它公开了与
List
几乎相同的功能,只是它意味着同时使用。

如果您想思考 为什么 列表可能不是线程安全的,请记住

List<T>
实例由数组 (
T[]
) 支持 - 我们称之为
arr
。第一个
Add
调用有点像
arr[0] = value
,第二个有点像
arr[1] = value
,等等。但是列表有一个内部状态,即它知道其中有多少项,所以下一个索引是什么应该是下次有人打电话的时候
Add
,所以在我们的例子中,操作实际上更像是

arr[this.currentIndex] = value;
this.currentIndex += 1;

现在,如果 2 个线程尝试同时执行此操作会发生什么?经典的竞争条件 - 两者都会看到相同的

this.currentIndex
值,因此两者都会设置相同的数组元素,然后它们都会将该值增加 1。这并不是列表工作方式的非常准确的表示,但这只是一个简单的例子,说明未编写并发使用的代码如何在并发线程下崩溃。

© www.soinside.com 2019 - 2024. All rights reserved.