Java中的线程安全multithreading
鉴于以下多重:
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()方法的昂贵的同步和双重检查locking的争议,我们如何保持线程安全和懒惰呢? 这里提到了一个有效的单身人士的方式,但似乎并没有延伸到多人。
这将为您的Multitons提供一个线程安全的存储机制。 唯一的缺点是可以创build一个不会在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; }
更新:与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); } }
嗯,这很好!
原来的答案
这是一个build立在JCiP中描述的Memoizer模式的解决scheme。 它像使用其他答案一样使用ConcurrentHashMap,但不是直接存储Multiton实例,而是导致创build未使用的实例,而是存储导致创buildMultiton的计算。 额外的层解决了未使用实例的问题。
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(); } }
你可以使用一系列的锁,至less可以同时获得不同的实例:
private static final Multiton[] instances = new Multiton[...]; private static final Object[] locks = new Object[instances.length]; static { for (int i = 0; i < locks.length; i++) { locks[i] = new Object(); } } private Multiton(...) { //... } public static Multiton getInstance(int which) { synchronized(locks[which]) { if(instances[which] == null) { instances[which] = new Multiton(...); } return instances[which]; } }
随着Java 8的出现以及ConcurrentMap
和lambdas的一些改进,现在可以以更加整洁的方式实现一个Multiton
(甚至可能是一个Singleton
):
public class Multiton { // Map from the index to the item. private static final ConcurrentMap<Integer, Multiton> multitons = new ConcurrentHashMap<>(); private Multiton() { // Possibly heavy construction. } // Get the instance associated with the specified key. public static Multiton getInstance(final Integer key) throws InterruptedException, ExecutionException { // Already made? Multiton m = multitons.get(key); if (m == null) { // Put it in - only create if still necessary. m = multitons.computeIfAbsent(key, k -> new Multiton()); } return m; } }
我怀疑 – 虽然这会让我感觉不舒服 – getInstance
可以进一步减less到:
// Get the instance associated with the specified key. public static Multiton getInstance(final Integer key) throws InterruptedException, ExecutionException { // Put it in - only create if still necessary. return multitons.computeIfAbsent(key, k -> new Multiton()); }
你正在寻找一个AtomicReferenceArray 。
public class Multiton { private static final AtomicReferenceArray<Multiton> instances = new AtomicReferenceArray<Multiton>(1000); private Multiton() { } public static Multiton getInstance(int which) { // One there already? Multiton it = instances.get(which); if (it == null) { // Lazy make. Multiton newIt = new Multiton(); // Successful put? if ( instances.compareAndSet(which, null, newIt) ) { // Yes! it = newIt; } else { // One appeared as if by magic (another thread got there first). it = instances.get(which); } } return it; } }