多线程 C# 单例中的问题:未初始化的变量
Issue in C# singleton with multi threading: a variable not intialized
这是生产代码和运行在多线程和单线程中的简化版本。 与传统单例相比,额外的事情是我在 lock
部分初始化了客户端。
当我尝试通过Client client = Singleton.Instance.GetClient();
获取客户时,client
有可能为空(但机会很小) .
public class Client
{
public int Value { get; set; } = 10;
}
public class Singleton
{
private static Singleton instance = null;
private static readonly object padlock = new object();
private Client client = null;
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new Singleton();
// Here is the interesting part!
instance.InitClient();
}
}
}
return instance;
}
}
private void InitClient()
{
this.client = new Client();
}
public Client GetClient()
{
return this.client;
}
}
我是这样测试的:
static void Main(string[] args)
{
Console.WriteLine("Input thread count: ");
int threadCount = Int32.Parse(Console.ReadLine().Trim());
List<Task> tasks = new List<Task>(threadCount);
for (int i = 0; i < threadCount; ++i)
{
tasks.Add(Task.Factory.StartNew(() => DoStuff()));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("All threads complete");
}
private static void DoStuff()
{
Client client = Singleton.Instance.GetClient();
if (client.Value != 10)
{
Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}.");
}
}
客户端有时可以为空:
但是当我将InitClient()
移动到Singleton
的私有构造函数中时,我从未遇到过client为null的情况:
private Singleton()
{
this.InitClient();
}
我不知道有什么区别,有什么问题,感谢您的帮助!
一旦您在锁内调用 instance = new Singleton(),“instance”就不再为 null,这意味着立即对 Singleton.Instance returns 进行单独(线程化)调用,并调用到该实例上的 GetClient 将是与第一次调用的 InitClient 的竞争条件。
在构造函数内部进行初始化可确保“实例”本身在创建后立即进行初始化。因此来自不同线程的后续调用不会与任何东西竞争。
这是生产代码和运行在多线程和单线程中的简化版本。 与传统单例相比,额外的事情是我在 lock
部分初始化了客户端。
当我尝试通过Client client = Singleton.Instance.GetClient();
获取客户时,client
有可能为空(但机会很小) .
public class Client
{
public int Value { get; set; } = 10;
}
public class Singleton
{
private static Singleton instance = null;
private static readonly object padlock = new object();
private Client client = null;
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new Singleton();
// Here is the interesting part!
instance.InitClient();
}
}
}
return instance;
}
}
private void InitClient()
{
this.client = new Client();
}
public Client GetClient()
{
return this.client;
}
}
我是这样测试的:
static void Main(string[] args)
{
Console.WriteLine("Input thread count: ");
int threadCount = Int32.Parse(Console.ReadLine().Trim());
List<Task> tasks = new List<Task>(threadCount);
for (int i = 0; i < threadCount; ++i)
{
tasks.Add(Task.Factory.StartNew(() => DoStuff()));
}
Task.WaitAll(tasks.ToArray());
Console.WriteLine("All threads complete");
}
private static void DoStuff()
{
Client client = Singleton.Instance.GetClient();
if (client.Value != 10)
{
Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}.");
}
}
客户端有时可以为空:
但是当我将InitClient()
移动到Singleton
的私有构造函数中时,我从未遇到过client为null的情况:
private Singleton()
{
this.InitClient();
}
我不知道有什么区别,有什么问题,感谢您的帮助!
一旦您在锁内调用 instance = new Singleton(),“instance”就不再为 null,这意味着立即对 Singleton.Instance returns 进行单独(线程化)调用,并调用到该实例上的 GetClient 将是与第一次调用的 InitClient 的竞争条件。
在构造函数内部进行初始化可确保“实例”本身在创建后立即进行初始化。因此来自不同线程的后续调用不会与任何东西竞争。