Java Multiton模式使用的副作用
我需要你的建议,代码审查或对我的多通模式实现的改进。我想为mongodb服务器提供多连接支持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
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的机会。