1

我必须创建一个接受输入参数的单例。基本上我需要根据一些配置在库中创建一个 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;
}

}

编辑 写了一个多线程测试,所有线程都得到相同的实例。但是只是想确保我不会因为 Java 内存模型而错过任何边缘情况

4

1 回答 1

0

照原样,它在我看来合乎逻辑。

我觉得有趣的一件事是您使用单例模式可能会丢掉一个实例,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;
}
于 2017-05-14T08:33:21.077 回答