1

我遇到了一些这样的代码。

public class ConnectionUtility
{
    private static SqlConnection con;

    public static SqlConnection GimmeConnection()
    {
        if(con==null)
            con = new SqlConnection();
        return con;
    }
}

这是在 ASP.NET Web 应用程序中。是否可以期望存在竞争条件,其中一个请求/页面尝试打开/关闭连接上的执行操作,而其他请求也尝试执行这些操作?

4

5 回答 5

4

是的,那里绝对有可能出现竞争条件。多个线程可能同时调用GimmeConnection()并创建一个新连接,因此在初始化con.

在 .NET 中执行此操作的正确方法实际上相当简单:

public class ConnectionUtility
{
    private static SqlConnection con = new SqlConnection();

    public static SqlConnection GimmeConnection()
    {
        return con;
    }
}

这保证工作,没有任何竞争条件。

当然,还有另一种可能的竞态条件,这不是固定的:

因为您创建了一个全局可访问的连接,所以多个线程很容易同时使用它,这是不安全的。

如果连接被多个线程使用,则这些访问必须显式序列化,例如通过锁定。

当然,最好的做法仍然是首先避免单例......

于 2012-08-14T13:55:00.850 回答
1

是的...您不应该沿着多个线程共享单个静态连接。这不仅是一个竞争条件问题 - 您将有许多网页试图同时使用相同的连接,但这是行不通的。

您可以在“con”上使用 [ThreadStatic] 属性,这将使其在线程范围内具有全局性。

于 2012-08-14T13:54:29.463 回答
1

是的,你可以期待这样的竞争条件。好点子!

于 2012-08-14T13:55:14.470 回答
1

两种竞争条件,一种可能无害,一种可怕。还有一个逻辑错误。

潜在无害的是在构造函数逻辑中:

if(con==null)
  con = new Thing();

如果您想使用单个对象作为优化,这可能是无害的,但是有一段时间使用多个对象仅仅是次优而不是错误的(并非每场比赛都是世界末日)。这取决于它是什么Thing以及如何使用它。

灾难性的比赛是:

return con;

因为在这种情况下类型是SqlConnection,它不是线程安全的,所以每次使用该属性都是一场正在招致灾难的竞赛。

逻辑错误在于让单例缓存一个对象,该对象生成起来很轻,并且它处理自己的线程安全池的重部分。由于这种汇集,你不应该坚持SqlConnection超过绝对必要的时间。事实上,如果你在一次使用和另一次使用之间存在差距(虽然本身就是一种难闻的气味),你应该关闭它并重新打开它。这使得SqlConnection为​​您提供的线程安全池在使用之间以最佳状态工作。

于 2012-08-14T14:29:09.537 回答
0

每当编写单例时,您应该使它们成为线程安全的:

  class Singleton 
  {
    private Singleton() { }
    private static volatile Singleton instance;

    public static Singleton GetInstance() 
    {
       // DoubleLock
       if (instance == null) 
       {
          lock(m_lock) {  
             if (instance == null) 
             { 
                instance = new Singleton();
             }   
          }
       }
       return instance;
    }

    // helper
    private static object m_lock = new object();
  }
于 2012-08-14T13:56:24.520 回答