问题,假设我有线程A和线程B,这两个都需要访问单个对象及其属性。
目前单身人士看起来如下。
public class Singleton{
#region fields
private static Singleton singletonObject;
private double value1= 0;
private double value2= 0;
private double value3= 0;
private double value4= 0;
private object locker = null;
#endregion
// private constructor. This will avoid creating object using new keyword
private Singleton() {
locker = new object();
}
// public method which will be called
public void GetName() {
Console.WriteLine("singleton Object");
}
public static Singleton Instance() {
// this object will be used with lock, so that it will be always one thread which will be executing the code
object instanceLocker = new object();
// put a lock on myObject. We won't be able to use singleTonObject becuase it will be null. lock is to make the object thread safe.
// lock can't be worked with null objects.
lock (instanceLocker) {
// check whether the instance was there. If it's not there, then create an instance.
if (singletonObject == null) {
singletonObject = new Singleton();
}
}
return singletonObject;
}
public double Value1 { get { lock (locker) { return value1; } } set { lock (locker) { value1= value; } } }
public double Value2 { get { lock (locker) { return value2; } } set { lock (locker) { value2= value; } } }
public double Value3 { get { lock (locker) { return value3; } } set { lock (locker) { value3= value; } } }
public double Value4 { get { lock (locker) { return value4; } } set { lock (locker) { value4= value; } } }
}
我的问题。而不是具有线程安全属性,是否有更好的方法?
谢谢,
答案 0 :(得分:4)
目前您的代码已完全破解。您正在创建一个新对象,以便在每次调用期间锁定。没有其他线程会知道它,所以它完全没有意义。
不要试图以巧妙的方式解决它。只需在静态变量初始值设定项中初始化它:
private static Singleton singletonObject = new Singleton();
美好而简单。
有关在C#中实现单例模式的更多信息(包括在.NET 4中使用Lazy<T>
),请参阅my article on the topic。
答案 1 :(得分:2)
除了你为每次调用创建一个新对象以锁定之外,还有另一个基本问题:即使你拥有相同的对象,你仍然没有真正保护任何东西。
在该行的某处,您将Value1
初始化为9:
Singleton.Instance().Value1 = 9;
现在假设您有两个执行此代码的线程:
public void Foo()
{
Singleton.Instance().Value1++;
if(Singleton.Instance().Value1==10.0)
{
Singleton.Instance().Value2 = 20.0;
}
else
{
Singleton.Instance().Value3 = 30.0;
}
}
线程A调用Value1++
并将value1递增到10.0
线程B调用Value1++
,现在值1是11.0
线程A检查值value1是否为10.0 - &gt;返回false!
线程A将Value3
设置为30
线程B也将Value3
设置为30。
这只是一个非常简单的示例,其中锁定属性不会保护您,因为外部代码不会保证读取或写入事物的顺序。可能存在许多其他顺序,其中执行线程A和线程B将导致完全不同的结果。
这种行为可能没问题,因为你可以让Singleton
类的用户负责确保你班级以外的正确操作,但这通常是你应该注意的事情。简单地锁定属性不会消除读/写争用。
答案 2 :(得分:1)
您使用的是.NET 4.0吗?您可以使用ConCurrent集合进行线程安全活动,而不是锁定。