2010-12-19 6 views
10

가능한 중복 :
Efficient way to implement singleton pattern in Java스레드 안전 Java에서 싱글 톤 패턴을 효율적으로 구현할 수 있습니까?

나는이 Best Singleton Implementation In Java을 읽고 있었다,하지만 스레드로부터 안전하지 않습니다. 위키 당으로

: 1. 더블 널 (null) 검사 :

if(singleton==null) { synchronized(Singleton.class) { // this is needed if two threads are waiting at the monitor at the // time when singleton was getting instantiated if(singleton==null) singleton= new Singleton(); }
}

그러나 버그 유틸리티를 찾기는이 두 가지 오류를 제공합니다. 2. 정적 필드의 지연 초기화가 잘못되었습니다.

synchronized (Singleton.class) { 
if (singleton== null) { 
singleton= new Singleton(); 
} 
} 
+1

위의 질문과 중복됩니다. 자세한 내용은 해당 질문을 참조하십시오. 하지만이 질문에 유용한 링크가 있는지는 잘 모르겠습니다. [Java의 이중 체크 잠금] (http://www.ibm.com/developerworks/java/library/j-dcl.html)에 링크되어 있습니다. [these] (http://www.ibm.com/developerworks/library/j-jtp02244.html) Java 용 [two] (http://www.ibm.com/developerworks/library/j-jtp03304/) 업데이트 5. [위키피디아의 이중 잠금에 관한 기사] (http://en.wikipedia.org/wiki/Double-checked_locking)도 참조하십시오. 그러나 귀하의 질문에 대한 실제 답변은 위에 링크 된 질문을 참조하십시오. –

답변

20

가장 효율적인/간단한 방법은 싱글 그냥

enum Singleton { 
    INSTANCE 
} 

이다 게으른 로딩을 할 : 가장 좋은 방법은 무엇

,

는 수정을가 주 : 클래스 로딩은 스레드로부터 안전하므로 잠금 할 필요가 없습니다. 클래스는 기본적으로 final이며 생성자는 리플렉션을 통해 호출 할 수 없습니다. INSTANCE는 클래스 또는 클래스가 사용될 때까지 작성되지 않습니다. 클래스가 우연히 사용되었다고 걱정되면 내부 클래스에서 싱글 톤을 래핑 할 수 있습니다.

final class Singleton { 
    private Singleton() { } 
    static class SingletonHolder { 
     static final Singleton INSTANCE = new Singleton(); 
    } 
    public static Singleton getInstance() { 
     return SingletonHolder.INSTANCE; 
    } 
} 

IMHO, 이건 더 나은 해결책이라고 생각하면 꽤 편집증이 있어야합니다.

+0

두 번째 코드에서'enum'을 사용하지 않고'class'를 사용하고 있으므로 가져 오는 방법이 혼란 스럽습니다. 한 번 클래스를 초기화하고 다음 번에 해당 객체를 호출하도록 열거 형을 만들고 싶습니다. 어떻게 할 수 있습니까? 예를 들어주십시오. – manish

+0

@Manish 그 경우에는 내가했던 것처럼 '열거 형'을 사용하십시오. 첫 번째 예. –

+0

괜찮아요.하지만 어떻게 한 번 클래스를 초기화하고 다음 번에 그 인스턴스를'enum'을 사용하여 사용할 수 있습니까? 그게 내 confusion.every 어디 그냥'열거 형 싱글 톤 { 인스턴스가 }'이 많이 있지만 개체를 ​​호출하고 초기화하는 방법을 참조하십시오 – manish

2

Efficient way to implement singleton pattern in Java에 대한 대답의 첫 번째 코드 샘플은 스레드로부터 안전합니다. INSTANCE의 생성은 클래스가 처음로드 될 때 클래스 로더에 의해 수행됩니다. 정확히 한 번 수행, 그리고 스레드 안전한 방법 :

public final class Foo { 

    private static final Foo INSTANCE = new Foo(); 

    private Foo() { 
     if (INSTANCE != null) { 
       throw new IllegalStateException("Already instantiated"); 
     } 
    } 

    public static Foo getInstance() { 
     return INSTANCE; 
    } 
} 

(What is an efficient way to implement a singleton pattern in Java?에서 복사)

질문에서 제 2 회 코드 샘플은 정확하고 스레드 안전하지만, 그것은 각각의 호출에 동기화를 발생 ~ getInstance()으로 설정하면 성능에 영향을줍니다.

+0

개인 생성자를 보호하지 않는 것은 상당히 편집 적이기 때문입니다. 리플렉션을 사용하여 다른 인스턴스를 만드는 것을 피하는 것으로 가정하거나 내부 클래스가 생성자를 호출하는 것을 중단 할 것입니까? –

+0

이전 질문에서 답을 논의하고 있었으므로 코드를 그대로 복사했습니다. 개인적으로 나는 if (INSTANCE! = null) 체크도 생략 할 것이다. –

+0

및 그 때문에 예외가 있다고 가정합니다. ;) –

3

이 문제에 관해 많이 쓰여졌습니다. 그렇습니다. 단순한 이중 체크 잠금 패턴은 안전하지 않습니다. 하지만 정적 인스턴스를 volatile로 선언하여 안전하게 만들 수 있습니다. 새로운 Java 메모리 모델 사양은 휘발성을 처리 할 때 컴파일러에 대한 코드 재 배열 제한을 추가하므로 원래의 위험은 사라졌습니다. 인스턴스를 만들 때

어쨌든, 난 거의 정말 그렇게 나는 보통 단순히 클래스 로딩 시간에 정적을 만들고, lazyness의이 종류를 필요

private static MyClass instance = new MyClass(); 

이 짧고 분명하다.당신은 정말 게으른 있도록하려면 다른 방법으로, 당신은 클래스 로딩 특성을 활용하고이 작업을 수행 할 수 있습니다

public class MyClass { 
    private static class MyClassInit { 
     public static final MyClass instance = new MyClass(); 
    } 

    public static MyClass getInstance() { 
     return MyClassInit.instance; 
    } 
... 
} 

중첩 된 클래스는 당신의 getInstance를 호출 처음 할 때까지로드()되지 않습니다.

관련 문제