使用 DI 为控制台编写了一个小应用程序。应用程序从 DI 容器中变异并公开单例状态。
程序.cs
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<ISingletonTest, SingletonTest>();
serviceCollection.AddSingleton<App>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var app = serviceProvider?.GetService<App>();
using (var scope = serviceProvider?.CreateScope())
{
app?.RUN();
}
我/SingletonTest.cs
public interface ISingletonTest
{
public int COUNT { get; }
public void increase();
}
class SingletonTest : ISingletonTest
{
private int _count = 0;
public int COUNT { get => _count; }
public void increase()
{
_count++;
}
}
应用程序
internal class App
{
private readonly ISingletonTest _singletonTest;
public App(ISingletonTest singletonTest)
{
_singletonTest = singletonTest;
}
public void RUN()
{
List<Thread> lst = new List<Thread>();
for (int i = 0; i < 100; i++)
{
lst.Add(new Thread(() =>
{
_singletonTest.increase();
Console.WriteLine("In thread:" + Environment.CurrentManagedThreadId + " value of _singletonTest.COUNT = " + _singletonTest.COUNT);
}));
}
foreach (var item in lst)
{
item.Start();
}
Console.ReadLine();
}
}
程序输出如下
我想了解为什么会发生这种情况,因为 ServiceCollection 使用基于 IList 的线程安全集合。而事实上数据显示的顺序可能是乱的,但肯定不能有重复。是的!输出有时正常,但有时读数会重复几次。帮助我理解 DI 容器中的线程安全问题。
这里的问题不是 DI,而是类本身没有实现线程安全。
例如,这是可以做到的。
并像这样测试一下。我稍微简化了代码,但是逻辑没有改变。
控制台输出如下
线程的执行顺序最初是无法保证的,但不会再有重复的数字。
一般来说,您不是在检查单例,而只是在类本身中检查类的线程安全性。我建议通过这种方式检查。
控制台输出是相同的,只是数字更加混乱,我不会在这里展示它。
也就是说,现在如果你删除单例。
然后就只有一个会被输出到控制台。但它不会改变测试中的任何内容
AddTransient
,因为App
它与其依赖项一样,只被解析一次。此外,如果将AddTransient
其中任何一个更改为AddSingleton
,那么将会有从 2 到 100 的数字,因为在一种情况下,您将有一个单例App
,它将解决其依赖关系一次,因为它是单独的。在第二种情况下,所有实例都App
将解析为同一个单例SingletonTest
。这可能就是您最初想要的,并且这是正确测试它ISingletonTest
确实是一个单例的方法: