2012-09-19 3 views
4

this topic을 기반으로, AtomicIntegers를 기반으로 구현 된 Singleton 패턴의 흥미로운 버전을 설명했습니다.이 싱글 톤은 스레드로부터 안전한 것입니까?

  • 이 구현 정확하고 스레드 안전하며, 일반적으로 스레드 동기화 및 관리를위한 원자 변수를 사용할 수있다 :

    질문은?

  • 추가 질문 :이 구현이 스레드로부터 안전하면 실제로 인스턴스 변수에 volatile 수정자가 필요합니까?
public class StrangeSingleton 
{ 

    private StrangeSingleton() {}; 

    private static volatile Object instance; 

    private static AtomicInteger initCounter = new AtomicInteger(); 
    private static AtomicInteger readyCounter = new AtomicInteger(); 

    static Object getInstance() 
    { 

     if (initCounter.incrementAndGet() == 1) 
     { 
      instance = new Object(); 

      readyCounter.incrementAndGet(); 

      return instance; 
     } 
     else if (readyCounter.get() == 1) 
     { 
      return instance; 
     } 
     else 
     { 
      //initialization not complete yet. 
      //write here some logic you want:    
      //sleep for 5s and try one more time, 
      //or throw Exception, or return null.. 

      return null; 
     } 
    } 
} 

UPDATE은 : 민간 생성자,하지만이 아닌 점을 추가했다.

+2

개인 생성자가 누락되었습니다! – Santosh

+0

누구나'new StrangeSingleton()'을 부를 수 있다면 어떻게 싱글 톤이 될 수 있을까요? 인수를 취하지 않는 전용 생성자를 만듭니다. – km1

+2

당신은'AtomicInteger' 대신'AtomicBoolean'을 사용할 수 있습니다. 'compareAndSet()'을 사용하십시오. – Gray

답변

8

이 구현은 정확하고 스레드로부터 안전하며 일반적으로 스레드 동기화 및 관리에 원자 변수를 사용할 수 있습니까?

변경 사항에 신속하게 대처하기 위해 바쁜 시간이 필요하기 때문에 일반적으로 복잡하지만 CPU 집약적입니다.

추가 질문 :이 구현이 스레드로부터 안전 할 경우 인스턴스 변수에 휘발성 수정 기호가 필요한가요?

AtomicInteger에 올바른 발생 전후 처리 동작을 보장하는 휘발성 필드가 포함되어 있기 때문에이 경우에는 그렇지 않습니다. 그냥 안전하고 훨씬 더 간단 스레드 열거를 사용할 수 물론


)

enum Singleton { 
    INSTANCE; 
} 
+0

피터 (Peter)는 성능면에서 일반적인 이중 체크 잠금 메커니즘과 어떻게 비교합니까? – Santosh

+0

두 개의 AtomicXxxxx를 확인하는 것보다 이중 체크 잠금이 빠릅니다. 'enum '을 사용하는 것은 휘발성 필드와 점검을 필요로하지 않기 때문에 가장 빠릅니다. –

+1

@Santosh 일부 구현 시맨틱 때문에 1.4 및 이전 버전의 모든 플랫폼에서 이중 잠금이 반드시 안전하지는 않습니다. ([Wikipedia article.] (http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java)) 이것은 5+에서 문제가되지 않습니다. 또한, +1 – Brian

2

이 구현 정확하고 스레드 안전하며, 일반적으로는 원자력을 사용할 수 있습니다 스레드 동기화 및 관리를위한 변수는 무엇입니까?

예,하지만 readyCounter 변수에 대해 당신은 아마 이런 CountDownLatch를 사용한다 :

기다리고 호출
private static AtomicInteger initCounter = new AtomicInteger(); 
private static CountDownLatch readyCounter = new CountDownLatch(1); 

static Object getInstance() 
{ 

    if (initCounter.incrementAndGet() == 1) 
    { 
     try { 
      instance = new Object(); 
      return instance; 
     } finally { 
      readyCounter.countDown(); 
     } 
    } 
    else 
    { 
     readyCounter.await(); 
     return instance; 
    } 
} 

는()는 초기화 경쟁 조건을 해결합니다. (또한 try-finally 블록을 사용하여 생성자 예외에서 교착 상태를 피할 수 있습니다.)

추가 질문 :이 구현이 스레드로부터 안전 할 경우 인스턴스 변수에 휘발성 수정 기호가 필요합니까?

인스턴스 변수에 액세스하기 전에 관련 AtomicInteger 또는 CountDownLatch 함수를 호출하면 안됩니다. 이 발생하기 전에 documentation 앞에 나타납니다.

+0

래치 덕분에 그레이트 오데아, 감사합니다, Soulman! – KutaBeach

0

스레드 T1은 T2는 아직 증가되지 않은 readyCounter 이후 else{} 블록을 칠 것이다 instance = new Object();에 중단 될 수 있습니다. 이 속성을 설정하면 해당 초기화 가 완료된 이후 꽤 정확하지, 어떤 뒤쳐진 것은 국가의 책 유지 나는 오히려 getInstance() 방법 중 하나 개 synchronized 블록을 할 것

0

입니다. 이것으로 충분합니다. @David가 알아 차린 것처럼 이상하지 않은이 이상한 카운터는 필요하지 않습니다.

관련 문제