2014-03-13 65 views
0

我需要您的建議,代碼審查或改進有關我的多重模式實現。我想要多連接支持MongoDB服務器。Multiton模式使用的副作用

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()); 
    } 
} 

多子模式的最佳實踐是什麼?

+0

[A MongoClient已經連接池(http://docs.mongodb.org/ecosystem/drivers/java-concurrency/),爲什麼你想/需要增加額外的層? – assylias

回答

1

As Marko Topolnik說,你目前的解決方案不是線程安全的。

我把這當成一個小練習,並且寫了下面的通用線程安全的Multition模式。它是否被設計爲在許多線程中表現良好,並且適用於價值對象創建昂貴的情況。請注意,我不確定在特定情況下沒有更簡單的解決方案。

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); 
    }  
    } 
} 
0

此行是不是線程安全的:

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

您將有哈希地圖上的數據在這裏比賽,因爲你沒有保護帶鎖定地圖的訪問。可能最好的解決方案是將其移入​​區塊。你不應該擔心這裏的表現,至少不是沒有一個確鑿的證據。

+0

你見過Java 8 multiton嗎? => http://stackoverflow.com/a/18149547/829571 – assylias

+0

啊,是的,這是我最大的挫折之一,我可以做一個Clojure單線程,但只能在Java中實現一個巨大的和笨重的代碼塊爲每個用法copypasted。當然,他們在這裏利用lambda的機會跳了起來。 –