Java Multiton模式使用的副作用

Java Multiton模式使用的副作用,java,design-patterns,concurrency,multiton,Java,Design Patterns,Concurrency,Multiton,我需要你的建议,代码审查或对我的多通模式实现的改进。我想为mongodb服务器提供多连接支持 public class MongoDatabaseFactory { private static volatile Map<String, MongoDatabase> connections = new ConcurrentHashMap<String, MongoDatabase>(); public static MongoDatabase getDa

我需要你的建议,代码审查或对我的多通模式实现的改进。我想为mongodb服务器提供多连接支持

public class MongoDatabaseFactory {
    private static volatile Map<String, MongoDatabase> connections = new ConcurrentHashMap<String, MongoDatabase>();

    public static MongoDatabase getDatabase(Databases database) throws MongoException {
        if (null == database) throw new MongoException("Database not found");
        if (null == database.name() || database.name().isEmpty()) throw new MongoException("Database not found");

        if (!connections.containsKey(database.name()) || null == connections.get(database.name())) {
            synchronized (database) {
                if (!connections.containsKey(database.name()) || null == connections.get(database.name())) {
                    connectDB(database);
                }
            }
        }

        if (!connections.get(database.name()).isAuthenticated()) {
            synchronized (database) {
                if (!connections.get(database.name()).isAuthenticated()) {
                    connectDB(database);
                }
            }
        }

        return connections.get(database.name());
    }
}
公共类MongoDatabaseFactory{
私有静态volatile映射连接=新ConcurrentHashMap();
公共静态MongoDatabase getDatabase(Databases database)引发MongoException{
如果(null==数据库)抛出新的MongoException(“未找到数据库”);
如果(null==database.name()| | database.name().isEmpty())抛出新的MongoException(“未找到数据库”);
if(!connections.containsKey(database.name())| | null==connections.get(database.name()){
已同步(数据库){
if(!connections.containsKey(database.name())| | null==connections.get(database.name()){
连接数据库;
}
}
}
如果(!connections.get(database.name()).isAuthenticated()){
已同步(数据库){
如果(!connections.get(database.name()).isAuthenticated()){
连接数据库;
}
}
}
返回connections.get(database.name());
}
}

multiton模式的最佳实践是什么

此行不是线程安全的:

if (!connections.containsKey(database.name()) || null == connections.get(database.name()))

您将在哈希映射上进行数据竞争,因为您没有使用锁保护映射访问。最好的解决方案可能是将其移动到
synchronized
块中。您不应该担心这里的性能,至少没有确凿的证据。

正如Marko Topolnik所说,您当前的解决方案不是线程安全的

我将此作为一个小练习,并编写了以下通用的线程安全多离子模式。它的设计是为了在多线程中运行良好,并且适合于创建价值对象的成本很高的情况。但是,请注意,我不确定在您的特定情况下是否有更简单的解决方案

import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;


public class ThreadSafeMultition <K, V> {
  private final ConcurrentHashMap<K, FutureTask<V>> map = new ConcurrentHashMap<K, FutureTask<V>>();
  private ValueFactory<K, V> factory;

  public ThreadSafeMultition(ValueFactory<K, V> factory) {
    this.factory = factory;
  }

  public V get(K key) throws InterruptedException, ExecutionException {
    FutureTask<V> f = map.get(key);
    if (f == null) {
      f = new FutureTask<V>(new FactoryCall(key));
      FutureTask<V> existing = map.putIfAbsent(key, f);
      if (existing != null)
        f = existing;
      else // Item added successfully. Now that exclusiveness is guaranteed, start value creation.
        f.run();
    } 

    return f.get();
  }

  public static interface ValueFactory<K, V> {
    public V create(K key) throws Exception;
  }

  private class FactoryCall implements Callable<V> {
    private K key;

    public FactoryCall(K key) {
      this.key = key;
    }

    @Override
    public V call() throws Exception {
      return factory.create(key);
    }    
  }
}
import java.util.concurrent.Callable;
导入java.util.concurrent.ConcurrentHashMap;
导入java.util.concurrent.ExecutionException;
导入java.util.concurrent.FutureTask;
公共类线程安全{
私有最终ConcurrentHashMap=新ConcurrentHashMap();
私人工厂;
public ThreadSafeMultion(ValueFactory工厂){
这个工厂=工厂;
}
public V get(K键)抛出InterruptedException、ExecutionException{
FutureTask f=map.get(键);
如果(f==null){
f=新未来任务(新工厂呼叫(关键));
FutureTask existing=map.putIfAbsent(键,f);
if(现有!=null)
f=现有的;
else//已成功添加项目。现在已保证独占性,开始创造价值。
f、 run();
} 
返回f.get();
}
公共静态接口工厂{
public V create(K键)抛出异常;
}
私有类FactoryCall实现可调用{
私钥;
公用FactoryCall(K键){
this.key=key;
}
@凌驾
public V call()引发异常{
返回工厂。创建(键);
}    
}
}

,为什么您想/需要添加一个额外的层?啊,是的,这是我最大的挫折之一,因为我可以使用Clojure one liner,但只能在Java中为每次使用复制粘贴大量笨拙的代码块。很自然,他们抓住了在这里利用lambda的机会。