静态 属性 作为 class 实例的线程安全考虑
Thread safety consideration for static property as an Instance of that class
请考虑此代码:
public class BusinessClass
{
static BusinessClass myClass { get; set; }
Repository repo;
public BusinessClass()
{
if (repo == null)
repo = new RepositoryClass();
}
public static BusinessClass Instance
{
get
{
if (myClass == null)
myClass = new BusinessClass();
return myClass ;
}
}
public void Update(Entity Item)
{
repo.Update(Item);
}
}
并且我想在我的网页中使用这个 BL
,如下所示:
BusinessClass.Instance.Update(Item);
我的问题是:这段代码是否存在线程安全问题? Update
方法可以两个人同时走到一起吗?
谢谢
它不是线程安全的。这只是可能发生的情况的一个示例:
Thread1: if (myClass == null)
<- receives true because it's null
Thread1: [temp1] = new BusinessClass();
<-- [temp1]
exists
implicitly in Thread 1
Thread2: if (myClass == null)
<- receives true because it's still
null
Thread2: [temp2] = new BusinessClass();
<-- [temp2]
exists
implicitly in Thread 2
Thread2: myClass = [temp2];
Thread2: return myClass;
<-- returns second instance created
Thread1: myClass = [temp1];
Thread1: return myClass;
<-- returns first instance created
现在每个线程都持有 "singleton" Instance
的不同实例。
一种易于使用的线程安全直接替代方法是使用 Lazy<BusinessClass>
来保存您的单例实例而不是 myClass
.
第一种情况——asp.net会话锁
如果您使用 asp.net 表单和 asp.net 的会话,则该会话将锁定所有用户的整个调用,因此您无需额外占用注意同步那个。
相关问题:
Does ASP.NET Web Forms prevent a double click submission?
Trying to make Web Method Asynchronous
Web app blocked while processing another web app on sharing same session
What perfmon counters are useful for identifying ASP.NET bottlenecks?
Replacing ASP.Net's session entirely
第二种情况——本地线程。
如果您不使用 asp.net 会话,或者 如果您在同一个调用中打开额外的线程,那么您需要锁定对静态数据的操作。
public class BusinessClass
{
private static readonly object oLock = new object();
static BusinessClass myClass { get; set; } = null;
Repository repo;
public BusinessClass()
{
if (repo == null)
repo = new RepositoryClass();
}
public static BusinessClass Instance
{
get
{
if myClass == null)
{
lock (oLock)
{
if myClass == null)
myClass = new BusinessClass();
}
}
return myClass
}
}
public void Update(Entity Item)
{
repo.Update(Item);
}
}
最终案例——全局变化
如果您希望仔细检查数据库或文件上的全局更改,或者任何可以通过模拟系统编辑更改的内容 - 在网络花园上运行的网络平台上(相同的多个池网站)...并忽略会话...
那么你需要mutex来同步所有调用。
通过使用 mutex,您还需要在更新之前检查记录是否仍然相同,如果不是,则表示其他人更改了它,当前用户将覆盖它。
更多需要考虑的因素 - 多用户环境。
想想这个场景。
用户A和B,加载相同的页面,相同的数据,各自改变。
用户将保存每个数据 - 不是同一时刻 - 但有很多时间不同。您写下的数据是最后保存的数据。其中一位用户将丢失他们的更改。
因此,如果您的用户更新相同的数据 - 超出锁定系统,您需要考虑更多并在多用户环境中制作更多的同步信号。
请考虑此代码:
public class BusinessClass
{
static BusinessClass myClass { get; set; }
Repository repo;
public BusinessClass()
{
if (repo == null)
repo = new RepositoryClass();
}
public static BusinessClass Instance
{
get
{
if (myClass == null)
myClass = new BusinessClass();
return myClass ;
}
}
public void Update(Entity Item)
{
repo.Update(Item);
}
}
并且我想在我的网页中使用这个 BL
,如下所示:
BusinessClass.Instance.Update(Item);
我的问题是:这段代码是否存在线程安全问题? Update
方法可以两个人同时走到一起吗?
谢谢
它不是线程安全的。这只是可能发生的情况的一个示例:
Thread1:
if (myClass == null)
<- receives true because it's nullThread1:
[temp1] = new BusinessClass();
<--[temp1]
exists implicitly in Thread 1Thread2:
if (myClass == null)
<- receives true because it's still nullThread2:
[temp2] = new BusinessClass();
<--[temp2]
exists implicitly in Thread 2Thread2:
myClass = [temp2];
Thread2:
return myClass;
<-- returns second instance createdThread1:
myClass = [temp1];
Thread1:
return myClass;
<-- returns first instance created
现在每个线程都持有 "singleton" Instance
的不同实例。
一种易于使用的线程安全直接替代方法是使用 Lazy<BusinessClass>
来保存您的单例实例而不是 myClass
.
第一种情况——asp.net会话锁
如果您使用 asp.net 表单和 asp.net 的会话,则该会话将锁定所有用户的整个调用,因此您无需额外占用注意同步那个。
相关问题:
Does ASP.NET Web Forms prevent a double click submission?
Trying to make Web Method Asynchronous
Web app blocked while processing another web app on sharing same session
What perfmon counters are useful for identifying ASP.NET bottlenecks?
Replacing ASP.Net's session entirely
第二种情况——本地线程。
如果您不使用 asp.net 会话,或者 如果您在同一个调用中打开额外的线程,那么您需要锁定对静态数据的操作。
public class BusinessClass
{
private static readonly object oLock = new object();
static BusinessClass myClass { get; set; } = null;
Repository repo;
public BusinessClass()
{
if (repo == null)
repo = new RepositoryClass();
}
public static BusinessClass Instance
{
get
{
if myClass == null)
{
lock (oLock)
{
if myClass == null)
myClass = new BusinessClass();
}
}
return myClass
}
}
public void Update(Entity Item)
{
repo.Update(Item);
}
}
最终案例——全局变化
如果您希望仔细检查数据库或文件上的全局更改,或者任何可以通过模拟系统编辑更改的内容 - 在网络花园上运行的网络平台上(相同的多个池网站)...并忽略会话...
那么你需要mutex来同步所有调用。
通过使用 mutex,您还需要在更新之前检查记录是否仍然相同,如果不是,则表示其他人更改了它,当前用户将覆盖它。
更多需要考虑的因素 - 多用户环境。
想想这个场景。
用户A和B,加载相同的页面,相同的数据,各自改变。
用户将保存每个数据 - 不是同一时刻 - 但有很多时间不同。您写下的数据是最后保存的数据。其中一位用户将丢失他们的更改。
因此,如果您的用户更新相同的数据 - 超出锁定系统,您需要考虑更多并在多用户环境中制作更多的同步信号。