2013-06-13 2 views
-1

Java에서 키워드 staticvolatile에 익숙해지기 시작했습니다. 내가 만들고있는 싱글 톤 클래스와 관련하여 왜 다음과 같은 디자인을 볼 수 있습니까?싱글 톤 인스턴스 인스턴스화

public class Singleton{ 
    private static volatile Singleton _instance; 

    public static Singleton getInstance(){ 

     if(_instance == null){ 
      synchronized(Singleton.class){ 
       if(_instance == null) 
        _instance = new Singleton(); 
      } 

     } 
     return _instance; 

    } 
} 

대신이 하나?

public class Singleton{ 
    private static volatile Singleton _instance = new Singleton(); 

    public static Singleton getInstance(){ 
     return _instance; 
    } 
} 

첫 번째 디자인은 두 번째 디자인보다 이점이 있습니까? 내가 볼 수있는 유일한 장점은 두 번째 디자인이 전체 메서드를 동기화하므로 전체 메서드를 차단해야한다는 것입니다. 그러나 그 방법에 대한 나의 생각은이 방법이 단 한 줄에 지나지 않으므로 눈에 띄게 차단되지 않는다는 것입니다.

+0

"눈에 띄게 차단되는"의미는 무엇입니까? 어셈블리 언어로 된 지시 시간에주의 할 수 없다고해서 실생활에서 중요하지 않다는 것을 의미하지는 않습니다. –

+0

첫 번째 예제에서는 null _instance에 대한 두 가지 검사가 필요하지 않을 것이라고 확신합니다. 따라서 두 번째 검사는 제거 될 수 있습니다. 이 클래스에는 인스턴스가 new'd에서 null로 이동할 수있는 방법이 없습니다. –

+0

@ user619818 두 번째 검사가 필요합니다. 이전 검사 이후 다른 스레드가 이미 인스턴스를 초기화했을 수 있기 때문입니다. –

답변

2

코멘트를 추가하는 편이 좋았지 만 아직 그 일을 할 수없는 것 같습니다.

J2SE 5.0,이 문제가 해결되었습니다 :

첫 번째 예는 더 이상 자바 파괴하지 두 번 확인 잠금입니다. volatile 키워드는 이제 여러 스레드가 singleton 인스턴스를 올바르게 처리하도록합니다. ~ http://en.wikipedia.org/wiki/Double-checked_locking 두 번 확인 잠금의 아이디어가 필요할 때까지 싱글 톤 객체를 생성에 보류하고, 가능한 한 작은 동기와 목적을 잠그는 것입니다

.

두 번째 예제는 사용 여부에 관계없이 클래스가로드되는 즉시 (시작시) 시작할 수 있습니다.

두 예제 모두 스레드로부터 안전하며 J2SE 5.0 이상에서는 완벽하게 사용할 수 있습니다. 그것은 단지 싱글 톤 객체를 생성하는 비용을 감수하고, 사용되지 않는 객체를 메모리에 보유하는 날씨는 허용됩니다.

0

사실 두 번째 인스턴스는 "게으른"초기화를 수행하므로 클래스 인스턴스화에 많은 시간이 소요될 수 있으므로 응용 프로그램에서이 클래스의 인스턴스가 필요한지 확실하지 않습니다. 이 경우 "주문형"인스턴스를 생성 할 수 있습니다. 멀티 스레딩 환경에 따라 두 디자인 모두 스레드로부터 안전합니다.

0

첫 번째 예제는 다중 스레드 응용 프로그램에 유용하지만 이 아니므로 volatile 키워드를 사용하면 안전하지 않습니다. double-checked locking singleton 패턴입니다.

아이디어는 다음과 같습니다. - 객체가 null인지 확인하여 반환하지 않고 잠금을 피하십시오. - null 인 경우 자물쇠 잠금 클래스를 잠급니다. - null 인 경우 다른 스레드가 현재 스레드 전에 잠글 수 있기 때문에 다시 확인하십시오. - 여전히 null 인 경우 인스턴스화하십시오.

휘발성을 사용하면 다른 스레드가 이전 스레드가 완료 될 때까지 변수를 읽지 않도록 보장하지만 여전히 잠금 및 동기화는 CPU 시간의 값 비싼 작업입니다.

public class Singleton { 
    // Private constructor prevents instantiation from other classes 
    private Singleton() { } 

    /** 
    * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
    * or the first access to SingletonHolder.INSTANCE, not before. 
    */ 
    private static class SingletonHolder { 
      public static final Singleton INSTANCE = new Singleton(); 
    } 

    public static Singleton getInstance() { 
      return SingletonHolder.INSTANCE; 
    } 
} 

그것은 스레드 안전하고 할 수있는 올바른 방법 :

을 수행하는 적절한 방법은 빌 퓨의 솔루션을 사용하는 것입니다. 내부 클래스는 참조 될 때만로드되고 정적 키워드는 클래스 당 하나의 인스턴스 만 보장하므로 지연 초기화입니다.

두 번째 예제가 작동하지만 느리게 초기화되지 않았습니다.

+0

왜 INSTANCE 변수를 휘발성으로 지정할 필요가 없습니까? 각 스레드가 INSTANCE의 자체 캐시를 가지고있을 수 있으며 오래 가지 않을 수 있습니까? – BarryBostwick

+0

'volatile'은 이전 쓰레드가 끝날 때까지 다른 쓰레드가 그것을 읽지 않도록 보장한다. – darijan

+0

INSTANCE를 휘발성으로 설정하지 않고 두 스레드가 동시에 인스턴스를 수정하고 서로 겹쳐 쓸 수 없습니까? – BarryBostwick

관련 문제