1

有人可以检查这个版本的 Generic Multiton 是否是惰性的和线程安全的?

我根据Jon Skeet 的惰性线程安全 Singleton 版本、O'Reilly 的 C# Design Patterns 和 Multiton 的 Wikipedia C# 版本对其进行了编码。

public sealed class Multiton<T> where T : class, new() {
    private static readonly Dictionary<object, Lazy<T>> _instances = new Dictionary<object, Lazy<T>>();
    public static T GetInstance(object key) {
        Lazy<T> instance;
        if (!_instances.TryGetValue(key, out instance)) {
            instance = new Lazy<T>(() => new T());
            _instances.Add(key, instance);
        }
        return instance.Value;
    }
    private Multiton() {
    }
}
4

6 回答 6

1

Dictionary不是为多线程访问而设计的,而且您没有同步访问,所以不,当同时访问时,它不会总是按预期工作。

最简单的解决方案是使用 aConcurrentDictionary而不是 a Dictionary

于 2013-05-23T14:14:40.110 回答
1

我是 multiton 概念的新手,并质疑它的必要性。也就是说,您可以通过使用 a 来显着改善这一点ConcurrentDictionary<T>,如下所示:

public sealed class Multiton<T> where T : class, new() {
    private static readonly ConcurrentDictionary<object, Lazy<T>> _instances = 
        new ConcurrentDictionary<object, Lazy<T>>();
    public static T GetInstance(object key) {
        return _instances.GetOrAdd(key, k=>new Lazy<T>(() => new T())).Value;
    }
    private Multiton() {
    }
}

这很棒,因为如果同时调用 GetOrAdd,即使有机会Lazy<T>在同一个键上生成两个 s,但 GetOrAdd 只会添加/返回一个,这意味着这个并行添加的成本只是一个一次性的 Lazy 还没有它的值被实例化。这就是为什么保留Lazy<T>对于使其正常工作至关重要的原因。阅读内容以获取更多信息。

于 2013-05-23T14:15:36.177 回答
1

使用ConcurrentDictionary使您的字典线程安全。

于 2013-05-23T14:15:42.573 回答
1

对 的访问Dictionnary不同步。你应该锁定它:

    public static T GetInstance(object key) {
        lock (_instances) {   
           Lazy<T> instance;
           if (!_instances.TryGetValue(key, out instance)) {
               instance = new Lazy<T>(() => new T());
               _instances.Add(key, instance);
           }
        }
        return instance.Value;
    }
于 2013-05-23T14:17:52.560 回答
1

Dictionary 类不是线程安全的,您可以使用 ConcurrentDictionary 自动检查元素是否在字典中并从字典中添加/获取值:

public sealed class Multiton<T> where T : class, new() {
    private static readonly ConcurrentDictionary<object, Lazy<T>> _instances = new ConcurrentDictionary<object, Lazy<T>>();

    public static T GetInstance(object key) {
        Lazy<T> instance = _instances.GetOrAdd(key, k => new Lazy<T>(() => new T()));
        return instance.Value;
    }

    private Multiton() {
    }
}
于 2013-05-23T14:18:25.620 回答
0

我在想,这不是基于 Jon Skeet 的原始惰性线程安全单例的更准确的线程安全多例实现吗?

要完全惰性,静态字典需要惰性,这是原始单例的类比。字典成员还需要懒惰地处理不太可能但可能的双重实例化问题

这是我提出的一个完全通用的实现。

public sealed class Multiton<TKey, TInstance>
    where TInstance : class, new()
{
    private static readonly
        Lazy<ConcurrentDictionary<TKey, Lazy<TInstance>>> dic =
            new Lazy<ConcurrentDictionary<TKey, Lazy<TInstance>>>(
                () => new ConcurrentDictionary<TKey, Lazy<TInstance>>());

    public static TInstance Instance(TKey key)
    {
        return dic.Value.GetOrAdd(
            key, 
            k => new Lazy<TInstance>(() => new TInstance())).Value;
    }

    private Multiton()
    {
    }
}
于 2013-05-23T15:36:53.450 回答