Java 使用原子引用的带参数的单例

Java 使用原子引用的带参数的单例,java,multithreading,singleton,atomicreference,Java,Multithreading,Singleton,Atomicreference,我必须创建一个接受输入参数的单例。基本上,我需要根据一些配置在库中创建一个DBConnector。现在,消费应用程序将此配置传递到库。基于传入的配置,我想创建一个DBConnector实例,然后在库中重用它。 我曾想过使用DI来处理这个问题,但当这个库初始化时,我不知道是否需要DB连接,如果不需要,我不想创建这个DBConnector。 一旦库被初始化,在一个getResponse(RequestType rt)调用中,我就会知道是否需要一个DBConnector(基于RequestType),

我必须创建一个接受输入参数的单例。基本上,我需要根据一些配置在库中创建一个DBConnector。现在,消费应用程序将此配置传递到库。基于传入的配置,我想创建一个DBConnector实例,然后在库中重用它。 我曾想过使用DI来处理这个问题,但当这个库初始化时,我不知道是否需要DB连接,如果不需要,我不想创建这个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;
}
公共类DBConnectorFactory
{
私有静态易失性DBConnector DBConnector=null;
私有静态AtomicReference AtomicReference=新的AtomicReference();
私有DBConnectorFactory()
{}
公共静态DBConnector getDBConnector(DBConfig DBConfig)
{
if(dBConnector==null)
{
if(atomicReference.compareAndSet(null,新的DBConnector(dBConfig)))
dBConnector=atomicReference.get();
返回atomicReference.get();
}
其他的
返回dbc连接器;
}
}

编辑
编写了一个多线程测试,所有线程都得到了相同的实例。然而,我只是想确保我没有因为Java内存模型而遗漏任何边缘情况,我觉得它在逻辑上是合理的

我发现一件有趣的事情是,如果你输掉了一场比赛,使用第二个
原子引用#get()
,你可能会丢掉一个
DBConnector
实例。单例的全部目的不是确保只创建一个实例吗?如果这是您的意图,那么您使用的模式不适合此用途。您必须同步

否则,如果您坚持使用无锁初始化,并且可能有多个实例化,那么您应该只使用一个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;
}
私有静态AtomicReference实例=新的AtomicReference();
公共静态DBConnector getDBConnector(DBConfig DBConfig){
//初试
DBConnector con=instance.get();
如果(con==null){
con=/。。。
if(instance.compareAndSet(null,con)){
//交换成功,请返回我们的副本
返回con;
}否则{
//输掉比赛,再次投票
return instance.get():
}
}
//已然现值
返回con;
}

就目前情况而言,我觉得它在逻辑上是合理的

我发现一件有趣的事情是,如果你输掉了一场比赛,使用第二个
原子引用#get()
,你可能会丢掉一个
DBConnector
实例。单例的全部目的不是确保只创建一个实例吗?如果这是您的意图,那么您使用的模式不适合此用途。您必须同步

否则,如果您坚持使用无锁初始化,并且可能有多个实例化,那么您应该只使用一个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;
}
私有静态AtomicReference实例=新的AtomicReference();
公共静态DBConnector getDBConnector(DBConfig DBConfig){
//初试
DBConnector con=instance.get();
如果(con==null){
con=/。。。
if(instance.compareAndSet(null,con)){
//交换成功,请返回我们的副本
返回con;
}否则{
//输掉比赛,再次投票
return instance.get():
}
}
//已然现值
返回con;
}