Синглтон с аргументами, использующими 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;
}
Другие вопросы по тегам