문제

나는 읽고 있었다 이 기사 "Double-Checked Locking"과 기사의 주요 주제에서 기사의 어느 시점에서 저자가 다음 관용구를 사용하는지 궁금했습니다.

목록 7. 주문 외부 쓰기 문제를 해결하려고 시도합니다

public static Singleton getInstance()  
{
    if (instance == null)
    {
        synchronized(Singleton.class) {      //1
            Singleton inst = instance;         //2
            if (inst == null)
            {
                synchronized(Singleton.class) {  //3
                    inst = new Singleton();        //4
                }
                instance = inst;                 //5
            }
        }
    }
    return instance;
}

그리고 내 질문은 : 동일한 잠금으로 일부 코드를 두 번 동기화 할 이유가 있습니까? 이것이 어떤 목적이 있습니까?

미리 감사드립니다.

도움이 되었습니까?

해결책

두 번 잠그는 요점은 시도 주문 외부 쓰기를 방지합니다. 메모리 모델은 부분적으로 잠금면에서 재주문이 발생할 수있는 위치를 지정합니다. 잠금 장치는 "instance = inst"이후에 (싱글 톤 생성자 내에 어떤 것도 포함)가 발생하지 않도록합니다. 선.

그러나 주제에 대해 더 깊이 들어가기 위해 Bill Pugh의 기사. 그리고 그것을 시도하지 마십시오 :)

다른 팁

이 기사는 5.0 이전 Java 메모리 모델 (JMM)을 나타냅니다. 이 모델에서 동기화 된 블록을 남기는 것은 메인 메모리에 쓰기를 강제로 작성합니다. 따라서 싱글 톤 객체를 참조하기 전에 밀어 내려는 시도 인 것 같습니다. 그러나 인스턴스에 대한 쓰기가 블록 (Roach Motel)으로 올라갈 수 있기 때문에 작동하지 않습니다.

그러나 Pre-5.0 모델은 결코 올바르게 구현되지 않았습니다. 1.4는 5.0 모델을 따라야합니다. 수업은 게으르게 초기화되므로 글을 쓰는 것만으로도

public static final Singleton instance = new Singleton();

또는 더 나은, 싱글 톤을 사용하지 마십시오.

Jon Skeet은 옳습니다 : 읽기 Bill Pugh 's 기사. Hans가 사용하는 관용구는 작동하지 않습니다, 사용해서는 안됩니다.

이것은 안전하지 않습니다 :

private static Singleton instance;

public static Singleton getInstance() {
  if (instance == null) {
    synchronized(Singleton.class) {
      if (instance == null) {
        instance = new Singleton();
      }
    }
  }
  return instance;
}

이것은 또한 안전하지 않습니다 :

public static Singleton getInstance()  
{
    if (instance == null)
    {
        synchronized(Singleton.class) {      //1
            Singleton inst = instance;         //2
            if (inst == null)
            {
                synchronized(Singleton.class) {  //3
                    inst = new Singleton();        //4
                }
                instance = inst;                 //5
            }
        }
    }
    return instance;
}

그들 중 하나를하지 마십시오.

대신 전체 방법을 동기화하십시오.

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

이 객체를 검색하지 않는 한 초에 율을 차지하지 않는 한, 성능은 실제 용어로 무시할 수 있습니다.

나는 여기에서 이것을 다룹니다.

http://tech.puredanger.com/2007/06/15/double-checked-locking/

다음 존 스키트 추천:

그러나 주제에 대해 더 깊이 들어가기 위해 Bill Pugh의 기사를 추천합니다. 그리고 그것을 시도하지 마십시오 :)

그리고 다음은 두 번째 동기화 블록의 키입니다.

이 코드는 내부 동기화 블록 내부에 도우미 객체의 구성을 배치합니다. 여기서 직관적 인 아이디어는 동기화가 릴리스되는 시점에 메모리 장벽이 있어야하며, 이는 도우미 객체의 초기화와 필드 도우미에 대한 할당의 재정렬을 방해해야한다는 것입니다.

따라서 기본적으로 내부 동기화 블록을 사용하면 동기화 블록 내부의 인스턴스를 생성하는 JMM을 "치트"하려고 노력하여 JMM이 동기화 블록이 완료되기 전에 해당 할당을 실행하도록 강요합니다. 그러나 여기서 문제는 JMM이 우리를 향하고 있고 동기화 블록 내부의 동기화 블록 앞에있는 자제를 움직여서 문제를 시작 니그로 다시 움직이고 있다는 것입니다.

이것이 제가 그 기사에서 이해했던 것입니다. 정말 흥미롭고 다시 한 번 답장을 보내 주셔서 감사합니다.

좋아, 그러나 기사는 그렇게 말했다

Listing 7의 코드는 메모리 모델의 현재 정의로 인해 작동하지 않습니다. JLS (Java Language Specification)는 동기화 된 블록 내의 코드가 동기화 된 블록에서 이동하지 않도록 요구합니다. 그러나 동기화 된 블록에 있지 않은 코드는 동기화 된 블록으로 이동할 수 없다고 말하지는 않습니다.

또한 JVM이 ASM에서 "의사 코드"로 다음 번역을하는 것처럼 보입니다.

public static Singleton getInstance()
{
  if (instance == null)
  {
    synchronized(Singleton.class) {      //1
      Singleton inst = instance;         //2
      if (inst == null)
      {
        synchronized(Singleton.class) {  //3
          //inst = new Singleton();      //4
          instance = new Singleton();               
        }
        //instance = inst;               //5
      }
    }
  }
  return instance;
}

지금까지 "instance = inst"이후의 글이없는 요점은?

이제 기사를 읽을 것입니다. 링크에 감사드립니다.

Java 5이므로 필드 휘발성을 선언하여 두 번 확인 잠금 작업을 할 수 있습니다.

보다 http://www.cs.umd.edu/~pugh/java/memorymodel/doublecheckedlocking.html 전체 설명을 위해.

이 관용구와 관련하여 매우 권장적이고 명확한 기사가 있습니다.

http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html?page=1

다른 한편으로, Dhighwayman.myopenid가 의미하는 바는 작가가 동일한 클래스 (Synchronized (Singleton.class))를 동일한 클래스를 참조하는 다른 동기화 된 블록 내에 동기화 된 블록 하나를 넣은 이유라고 생각합니다. 해당 블록 내에서 새 인스턴스 (Singleton Inst = instance;)가 생성되어 스레드 안전을 보장하기 위해 다른 동기화 된 것을 작성해야합니다.

그렇지 않으면, 나는 어떤 의미도 볼 수 없습니다.

Google Tech Talk를 참조하십시오 자바 메모리 모델 JMM의 미세한 포인트에 대한 정말 좋은 소개. 여기서 누락되었으므로 Jeremy Mansons 블로그를 지적하고 싶습니다. 'Java 동시성' ESP. 게시물 이중 점검 잠금 (Java 세계에있는 사람은 누구나 이것에 관한 기사를 가지고있는 것 같습니다 :).

Java 5 이상의 경우 실제로 전체 액세서를 동기화하는 것보다 더 나은 이중 체크 변형이 있습니다. 이것은 또한 언급되어 있습니다 이중 확인 잠금 선언 :

class Foo {
    private volatile Helper helper = null;
    public Helper getHelper() {
        if (helper == null) {
            synchronized(this) {
                if (helper == null)
                    helper = new Helper();
            }
        }
        return helper;
    }
}

여기서 주요 차이점은 사용입니다 휘발성 물질 변수 선언에서 - 그렇지 않으면 작동하지 않으며 어쨌든 Java 1.4 이하에서는 작동하지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top