2010-06-02 4 views
8

Java에서 singleton 패턴을 구현할 때이 질문이 떠오른다. 아래에 나열된 예는 실제 코드가 아니지만 원래 코드와 매우 유사합니다. (또는 가능한 한 적은 등) 같은 클래스의 여러 정적 동기화 방법이 없습니다 - 나는 정적 동기화 방법의 행동에 대해 매우 확실하지 않다 때문에Java에서 정적 메서드를 동기화하는 방법

public class ConnectionFactory{ 
    private static ConnectionFactory instance; 

    public static synchronized ConnectionFactory getInstance(){ 
     if(instance == null){ 
      instance = new ConnectionFactory(); 
     } 

     return instance; 
    } 

    private ConnectionFactory(){ 
     // private constructor implementation 
    } 
} 

, 나는 구글에서 몇 가지 제안을 얻는다. 정적 동기화 메서드를 구현할 때 클래스 개체에 속한 잠금이 여러 개의 정적 동기화 된 메서드를 사용하여 시스템의 성능을 저하시킬 수 있으므로 사용하는 것이 좋습니다.

맞습니까? 또는 JVM 정적 동기화 된 메서드를 구현하는 다른 메커니즘을 사용합니까? 클래스에서 여러 개의 정적 동기화 된 메서드를 구현해야하는 경우 가장 좋은 방법은 무엇입니까?

감사합니다.

친절에 감사드립니다!

public class ConnectionFactory{ 
    private static ConnectionFactory instance = new ConnectionFactory(); 

    public static ConnectionFactory getInstance(){ 
     return instance; 
    } 

    private ConnectionFactory(){ 
    } 
} 

당신이 볼 수 있듯이, getInstance 방법에서 실제 필요 당신이 할 수있는 지금이 없다 : (가능한 코드에서 적은 수의 변경합니다)

+2

은 실제 코드는 초기화 지연에 관심 있습니까? 이는 대개 코드와 개발자의 시간 낭비이기 때문에; 선언에서 필드를 초기화하는 것은 99 %의 시간을 수행하는 올바른 작업이며 동기화가 필요하지 않게 만듭니다. –

답변

7

가장 좋은 방법은 다음과 같이하는 것입니다 동기화에 대한

public class ConnectionFactory{ 
    public static final ConnectionFactory INSTANCE = new ConnectionFactory(); 

    private ConnectionFactory(){ 
    } 
} 

UPD : 코드를 단순화

public class ConnectionFactory{ 
    private static final Object lock = new Object(); 

    public static void doSmth() { 
     synchronized (lock) { 

      ... 
     } 
    } 

    public static void doSmthElse() { 
     synchronized (lock) { 

      ... 
     } 
    } 
} 
: 가장 좋은 방법은 외부 클래스에 보이지 않는 잠금, 즉 동기를한다

"this에서 동기화하는 것이 나쁜 생각 인 이유는 무엇입니까?"(예 : this one)에 대한 토론이 많습니다. 클래스에 동기화하는 것이 실제로 동일하다고 생각합니다.

+0

유일한 생성자가 예외를 throw하는 경우 어떻게'인스턴스'를 만들겠습니까? – unbeli

+0

@ unbeli : 그것은 나쁘고 고쳐졌습니다. 그러나 올바른 해결책이 있다면 인스턴스가 필요하지 않은 경우에도 마찬가지입니다. – Roman

+0

@unbeli : 개인 정적 팩토리 메서드 또는 정적 이니셜 라이저 블록을 사용합니다. 유감스럽게도 Java 메모리 모델과 이중 검사 잠금에 관한 모든 논의는 수 백 개의 코드 샘플로 인터넷을 오염 시켰습니다. 이제는 초보자에게 getInstance() 메서드를 지연 초기화하는 것이 실제로 좋은 생각인지 또는 표준인지 여부를 알 수 있습니다. –

2

예, 정적 메서드는 클래스 개체에서 동기화됩니다. 아마 여기가 퍼포먼스에 대해 걱정하지 않을 것입니다, 아마도 이것이 당신의 퍼포먼스 핫스팟이되지는 않을 것입니다. 필요한 경우 언제 어디서나 간단하게 최적화하십시오.

2

정적 동기화 된 메서드는 클래스에 대한 잠금을 사용합니다. 예제의 경우 ConnectionFactory 클래스 객체의 잠금에 액세스합니다. 최선의 방법은 자물쇠보다 오래 자물쇠를 잡지 않는 것입니다. 동기화 된 메서드가 여러 개 있는지 여부는 문제가 아닙니다.

3

싱글 톤을 만들 수있는 몇 가지 방법이 있습니다.

한 권장되는 방법은 (하나 개의 인스턴스를 생성 보장) 열거 사용하는 것입니다

public enum ConnectionFactory { 

    INSTANCE; 

} 

또는 클래스로드 할 때 정적을 만들 수 있습니다

public class ConnectionFactory { 

    private static ConnectionFactory INSTANCE = new ConnectionFactory(); 

    private ConnectionFactory() {} 

    public static ConnectionFactory getInstance() { 
    return INSTANCE; 
    }  

} 

당신이 필요한 경우 느리게로드하십시오.이 관용구를 사용할 수 있습니다 (double checked locking anti-pattern 대신)

public class ConnectionFactory { 

    private static class ConnectionFactoryHolder { 
    private static ConnectionFactory INSTANCE = new ConnectionFactory(); 
    } 

    public static ConnectionFactory getInstance() { 
    return ConnectionFactoryHolder.INSTANCE; 
    } 

} 
0

Effective Java은 싱글 톤을 생성하기 위해 Enum을 사용하도록 권장합니다.그래서 코드는 다음과 같이 보일 것입니다 :

public enum ConnectionFactory{ 
INSTANCE; 

// Other factory methods go here. 

} 

}