Синглтон с аргументами, использующими AtomicReference
Я должен создать синглтон, который принимает входные аргументы. По сути, мне нужно создать DBConnector в библиотеке на основе некоторых настроек. Теперь эта конфигурация передается в библиотеку потребляющим приложением. Основываясь на переданной конфигурации, я хочу создать экземпляр DBConnector, который затем будет повторно использован в библиотеке. Я думал об использовании DI для обработки этого, но когда эта библиотека инициализируется, я не знаю, действительно ли требуется соединение с БД, и я не хочу создавать этот DBConnector, если он не требуется. Как только библиотека инициализирована, при вызове getResponse(RequestType rt) я узнаю, требуется ли DBConnector (на основе RequestType), и именно тогда мне нужно создать экземпляр. Таким образом, приведенный ниже код выглядит хорошо для многопоточной среды?
public class DBConnectorFactory
{
private static volatile DBConnector dBConnector = null;
private static AtomicReference<DBConnector> atomicReference = new AtomicReference<>();
private DBConnectorFactory()
{}
public static DBConnector getDBConnector(DBConfig dBConfig)
{
if(dBConnector == null)
{
if(atomicReference.compareAndSet(null,new DBConnector(dBConfig)))
dBConnector = atomicReference.get();
return atomicReference.get();
}
else
return dBConnector;
}
}
РЕДАКТИРОВАТЬ Написал многопоточный тест, и все потоки получают один и тот же экземпляр. Однако просто хочу убедиться, что я не пропускаю ни одного крайнего случая из-за модели памяти Java
1 ответ
Как это выглядит логично для меня.
Одна вещь, которую я нахожу интригующим, это то, что вы используете шаблон синглтона, который может DBConnector
если вы проиграете гонку и прибегните к помощи второго AtomicReference#get()
, Разве не единственная цель - гарантировать, что когда-либо будет создан только один экземпляр? Если это было вашим намерением, то шаблон, который вы используете, не подходит для этого. Вы должны синхронизировать.
В противном случае, если вы настаиваете на использовании инициализации без блокировок и потенциально имеете несколько экземпляров, вы должны просто использовать один AtomicReference, например, так:
private static AtomicReference<DBConnector> instance = new AtomicReference<>();
public static DBConnector getDBConnector(DBConfig dBConfig) {
// First try
DBConnector con = instance.get();
if (con == null) {
con = // ...
if (instance.compareAndSet(null, con)) {
// Successful swap, return our copy
return con;
} else {
// Lost the race, poll again
return instance.get():
}
}
// Already present value
return con;
}