Java 中的线程安全多元

给定以下多元数:

public class Multiton 
{
    private static final Multiton[] instances = new Multiton[...];

    private Multiton(...) 
    {
        //...
    }

    public static Multiton getInstance(int which) 
    {
        if(instances[which] == null) 
        {
            instances[which] = new Multiton(...);
        }

        return instances[which];
    }
}

我们如何保持线程安全和懒惰,而没有昂贵的getInstance()方法的同步和双重检查锁定的争议?这里提到了单例的有效方法,但这似乎并没有扩展到多例。


答案 1

更新:使用Java 8,它可以更简单:

public class Multiton {
    private static final ConcurrentMap<String, Multiton> multitons = new ConcurrentHashMap<>();

    private final String key;
    private Multiton(String key) { this.key = key; }

    public static Multiton getInstance(final String key) {
        return multitons.computeIfAbsent(key, Multiton::new);
    }
}

嗯,这很好!


原始答案

这是一个基于 JCiP 中描述的 Memoizer 模式构建的解决方案。它像使用其他答案之一一样使用 ConcurrentHashMap,但不是直接存储 Multiton 实例(这可能导致创建未使用的实例),而是存储导致创建 Multiton 的计算。该附加层解决了未使用实例的问题。

public class Multiton {

    private static final ConcurrentMap<Integer, Future<Multiton>> multitons = new ConcurrentHashMap<>();
    private static final Callable<Multiton> creator = new Callable<Multiton>() {
        public Multiton call() { return new Multiton(); }
    };

    private Multiton(Strnig key) {}

    public static Multiton getInstance(final Integer key) throws InterruptedException, ExecutionException {
        Future<Multiton> f = multitons.get(key);
        if (f == null) {
            FutureTask<Multiton> ft = new FutureTask<>(creator);
            f = multitons.putIfAbsent(key, ft);
            if (f == null) {
                f = ft;
                ft.run();
            }
        }
        return f.get();
    }
}

答案 2

这将为您提供多通的线程安全存储机制。唯一的缺点是可以创建一个不会在 putIfAbsent() 调用中使用的 Multiton。可能性很小,但确实存在。当然,在偶然的情况下,它确实发生了,它仍然不会造成伤害。

从好的方面来说,不需要预分配或初始化,也没有预定义的大小限制。

private static ConcurrentHashMap<Integer, Multiton> instances = new ConcurrentHashMap<Integer, Multiton>();

public static Multiton getInstance(int which) 
{
    Multiton result = instances.get(which);

    if (result == null) 
    {
        Multiton m = new Multiton(...);
        result = instances.putIfAbsent(which, m);

        if (result == null)
            result = m;
    }

    return result;
}

推荐