【问题标题】:Is this singleton implementation threadsafe - Check code [closed]这个单例实现线程安全吗 - 检查代码[关闭]
【发布时间】:2013-06-18 09:36:02
【问题描述】:

我有这个用于数据库连接的类实现。现在,这不是一个标准的 SQL 数据库。

我需要知道以下是否是一个好的实现,如果不是 - 为什么。

我需要一个带参数的单例类,我就是这样设计的。

class Connection 
{
    private string param1;
    private string param2;
    private static readonly IList<Connection> connections = new List<Connection>();
    private Connection()
    {
        //Prevent instantiation
    }

    private Connection(string param1, string param2)
    {
        this.param1 = param1;
        this.param2 = param2;
    }

    public static Connection getInstance(string param1, string param2)
    { 
        foreach(Connection c in connections)
        {
            if(c.param1 = param1 && c.param2 == param2)
                return c;
        }
        Connection new_conn = new Connection(param1, param2);
        connections.Add(new_conn);
        return new_conn;
    }
}

如下使用:

Connection c = Connection.getInstance(abc, xyz);
Connection d = Conn

*更新 - 现在可以了吗? *

class Connection 
{
    private string param1;
    private string param2;
    private static readonly ConcurrentDictionary<Tuple<string, string, string>, Connection> connections
        = new ConcurrentDictionary<Tuple<string, string>, Connection>();
    private Connection()
    {
        //Prevent instantiation
    }

    private Connection(string param1, string param2)
    {
        this.param1 = param1;
        this.param2 = param2;
    }

    public static Connection getInstance(string param1, string param2)
    { 
        Connection conn = activeConnections.GetOrAdd(new Tuple<string, string> 
            param1,param2), new Connection (param1, param2));
        return conn;
    }
}

【问题讨论】:

  • 投票为offtopic,属于codereview.stackexchange.com
  • @jgauffin 我不知道这样的网站存在。我将从这里发布。谢谢

标签: c# design-patterns thread-safety singleton


【解决方案1】:

不,它不是线程安全的 - 您在没有任何同步的情况下修改 List&lt;T&gt;,而 List&lt;T&gt; 不是线程安全的。

此外,您可能会得到两个具有相同参数的连接,如果两个呼叫同时进入,则都查看所有现有连接,然后都创建一个新连接。

我建议你使用ConcurrentDictionary,带有两个参数的元组的键。除此之外,这也会更有效率。

您可能想调用GetOrAdd 来获取现有连接或创建并添加新连接。

【讨论】:

  • 我会修改代码。这会解决线程问题吗?下面回复提到的锁呢?
  • @rtindru:使用ConcurrentDictionary 将为您处理线程问题,是的。不过,它确实要求您使用 .NET 4+。
  • 我是否也使用我的 2 个参数的串联作为键?我应该如何为密钥建模?
  • @rtindru:正如我在答案中所说,使用一个元组(所以在你的情况下,一个Tuple&lt;string, string&gt;)。或者,您也可以创建自己的课程。
  • @Sniffer:是的——ConcurrentDictionary 的目的是提供一个大部分无锁但线程安全的字典。考虑到我们基本上想要提供查找,使用字典也比使用列表更有效。如果列表变得很大并且您有很多线程,那么执行 O(N) 获取 同时持有锁 可能会很麻烦。
【解决方案2】:

这甚至不会编译,因为您的集合“连接”是非静态的?

也许这会好一点:

class Connection
{
    private readonly string param1;
    private readonly string param2;
    private  static readonly IList<Connection> connections = new List<Connection>();

    private Connection()
    {
        //Prevent instantiation
    }

    private Connection(string param1, string param2)
    {
        this.param1 = param1;
        this.param2 = param2;
    }

    public static Connection getInstance(string param1, string param2)
    {

        lock (connections)
        {
            var connection = connections.FirstOrDefault(c => c.param1.Equals(param1) && c.param2.Equals(param2));
            if (connection != null)
            {
                return connection;
            }
            else
            {
                var new_conn = new Connection(param1, param2);
                connections.Add(new_conn);
                return new_conn;
            } 
        }
    }

}

但是在 Connection 类中保存 Connection 类型的 List 对我来说似乎还是有点奇怪......

【讨论】:

    猜你喜欢
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多