关于单例及静态变量测试
服务端测试代码
静态类
public class StaticClass { public static int Count = 0; public static int SafeCount = 0; public static int GetCount() { return Count++; } private static readonly object lockObj = new object(); public static int SafeGetCount() { lock (lockObj) { return SafeCount++; } } }
单例服务
public class TestSerivceSingleton : ITestSerivceSingleton { public string Name { get; set; } public int Count { get; set; } private readonly ITestSerivceTransient testSerivceTransient; public TestSerivceSingleton(ITestSerivceTransient testSerivceTransient) { Name = Guid.NewGuid().ToString(); this.testSerivceTransient = testSerivceTransient; } //public TestSerivceSingleton() //{ // Name = Guid.NewGuid().ToString(); //} public string GetServiceName() { return "TestSerivceSingleton" +Name; } public string GetServiceNameChild() { return this.testSerivceTransient.GetServiceName(); } public int GetCount() { return Count++; } private readonly object lockObj = new object(); public int SafeCount = 0; public int SafeGetCount() { lock (lockObj) { return SafeCount++; } } }
测试代码
[Route("api/[controller]")] [ApiController] public class HomeController : ControllerBase { private readonly ITestSerivceSingleton testSerivceSingleton; private readonly ITestSerivceScoped testSerivceScoped; private readonly ITestSerivceTransient testSerivceTransient; private readonly ITestSerivceSingleton testSerivceSingleton1; private readonly ITestSerivceScoped testSerivceScoped1; private readonly ITestSerivceTransient testSerivceTransient1; public HomeController(ITestSerivceSingleton testSerivceSingleton,ITestSerivceScoped testSerivceScoped,ITestSerivceTransient testSerivceTransient, ITestSerivceSingleton testSerivceSingleton1, ITestSerivceScoped testSerivceScoped1, ITestSerivceTransient testSerivceTransient1) { this.testSerivceSingleton = testSerivceSingleton; this.testSerivceScoped = testSerivceScoped; this.testSerivceTransient = testSerivceTransient; this.testSerivceSingleton1 = testSerivceSingleton1; this.testSerivceScoped1 = testSerivceScoped1; this.testSerivceTransient1 = testSerivceTransient1; } [HttpGet("Index")] public IActionResult Index() { StringBuilder stringBuilder = new StringBuilder(); #region MyRegion //stringBuilder.AppendLine(testSerivceSingleton.GetServiceNameBase()); //stringBuilder.AppendLine(testSerivceSingleton.GetServiceName()); //stringBuilder.AppendLine(testSerivceSingleton1.GetServiceName()); //stringBuilder.AppendLine(testSerivceScoped.GetServiceNameBase()); //stringBuilder.AppendLine(testSerivceScoped.GetServiceName()); //stringBuilder.AppendLine(testSerivceScoped1.GetServiceName()); //stringBuilder.AppendLine(testSerivceTransient.GetServiceNameBase()); //stringBuilder.AppendLine(testSerivceTransient.GetServiceName()); //stringBuilder.AppendLine(testSerivceTransient1.GetServiceName()); //Transient作为Singleton成员 //stringBuilder.AppendLine(testSerivceSingleton.GetServiceNameChild()); //stringBuilder.AppendLine(testSerivceSingleton1.GetServiceNameChild()); //Singleton作为Transient成员 // stringBuilder.AppendLine(testSerivceTransient.GetServiceNameChild()); // stringBuilder.AppendLine(testSerivceTransient1.GetServiceNameChild()); //stringBuilder.AppendLine(testSerivceScoped.GetCount().ToString()); //stringBuilder.AppendLine(testSerivceTransient.GetCount().ToString()); #endregion stringBuilder.AppendLine($"非线程安全+单例:{testSerivceSingleton.GetCount().ToString()}"); stringBuilder.AppendLine($"非线程安全+静态变量:{StaticClass.GetCount().ToString()}"); stringBuilder.AppendLine($"线程安全+单例:{testSerivceSingleton.SafeGetCount().ToString()}"); stringBuilder.AppendLine($"线程安全+静态变量:{StaticClass.SafeGetCount().ToString()}"); return Content(stringBuilder.ToString()); } }
客户端模拟http请求
#region 多线程下静态变量/单例测试 #if true await Task.Run(async () => { int count = 100; while (count >= 0) { Console.Clear(); await Task.Delay(100); HttpClient httpClient = new HttpClient(); var response = await httpClient.GetAsync("http://localhost:5125/api/Home/Index"); if (response.StatusCode == HttpStatusCode.OK) { var message = await response.Content.ReadAsStringAsync(); Console.WriteLine(message); } count--; } }); #endif #endregion
启动WEB服务,并打开多个客户端模拟并发请求
结论
1、无论是单例对象的成员变量还是静态成员变量,所有请求都共用一个成员变量
2、在并发情况下,无论是单例对象的成员变量还是静态成员变量都存在线程安全问题
喜欢 C#、SQL、Web