作为该类的实例的静态属性的线程安全注意事项

时间:2018-12-18 12:33:20

标签: c# asp.net concurrency thread-safety c#-6.0

请考虑以下代码:

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方法同时聚在一起吗?

谢谢

2 个答案:

答案 0 :(得分:3)

第一种情况-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);
    }
}

最终案例-全球变化

如果您要仔细检查数据库或文件上的全局更改,或对系统进行模拟编辑后可能发生的任何更改,请在网络花园上运行的Web平台上(同一站点的多个池) ...而忽略会话...

然后,您需要mutex同步所有呼叫。

通过使用mutex,您还需要在更新之前检查记录是否仍然相同,如果不是,则表示其他人对其进行了更改,当前用户将覆盖它。

要考虑的更多内容-多用户环境。

请考虑这种情况。
用户A和B加载相同的页面,相同的数据,并且每一个都对其进行更改。

用户将要保存每个数据-不是同一时刻-而是要花费很多时间。您写下的数据是最后保存的数据。其中一位用户将丢失他们的更改。

因此,如果您的用户更新了相同的数据(超出了锁定系统),那么在多用户环境中,您还需要更多考虑并做出更多同步信号。

答案 1 :(得分:0)

不是线程安全的。这只是可能发生的情况的一个示例:

  

线程1:if (myClass == null) <-收到true,因为它为空

     

线程1:[temp1] = new BusinessClass(); <-[temp1]存在   隐式在线程1中

     

线程2:if (myClass == null) <-收到true,因为它仍然存在   空

     

线程2:[temp2] = new BusinessClass(); <-[temp2]存在   隐式在线程2中

     

线程2:myClass = [temp2];

     

线程2:return myClass; <-返回创建的第二个实例

     

线程1:myClass = [temp1];

     

线程1:return myClass; <-返回创建的第一个实例

现在,每个线程都拥有一个不同的“单例” Instance实例。


一种易于使用的线程安全直接替代方法是使用Lazy<BusinessClass>而不是myClass来保存您的单例实例。