静态 属性 作为 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,加载相同的页面,相同的数据,各自改变。

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

因此,如果您的用户更新相同的数据 - 超出锁定系统,您需要考虑更多并在多用户环境中制作更多的同步信号。