2017-05-12 6 views
1

입력 인수를 취하는 Singleton을 만들어야합니다. 기본적으로 일부 구성에 따라 라이브러리에 DBConnector를 만들어야합니다. 이제이 구성은 소비 응용 프로그램에서 라이브러리로 전달됩니다. 전달 된 구성을 기반으로 DBConnector 인스턴스를 만들어서 라이브러리에서 다시 사용하려고합니다. DI를 사용하여이 문제를 처리하려고 생각했지만이 라이브러리를 초기화 할 때 DB 연결이 실제로 필요한지 알지 못합니다. 필요하지 않은 경우이 DBConnector를 만들고 싶지 않습니다. 일단 라이브러리가 초기화되면 getResponse (RequestType rt) 호출에서 DBConnector가 필요한지 (RequestType을 기반으로) 필요한지와 인스턴스를 만들어야 하는지를 알게됩니다. 따라서 아래 코드는 multiThreaded 환경에 적합합니까?AtomicReference를 사용하는 인수가있는 싱글 톤

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 메모리 모델로 인해 어떤 엣지 케이스에서도 누락되지 않도록하고 싶습니다.

답변

0

마찬가지로 논리적으로 나에게 들립니다.

한 가지 흥미로운 점은 레이스를 잃고 두 번째 AtomicReference#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; 
}