문제

나는 이것을 발견했다 기사 Java에서 Double-Check Locking 패러다임이 깨진 이유에 대해 논의합니다. 패러다임은 .NET (특히 C#)에 유효합니까, 변수가 선언 된 경우 volatile?

도움이 되었습니까?

해결책

C#에서 싱글 톤 패턴 구현 세 번째 버전 에서이 문제에 대해 이야기합니다.

그것은 말한다 :

인스턴스 변동성 휘발성을 만드는 것은 명시 적 메모리 장벽 호출과 마찬가지로 작동 할 수 있지만, 후자의 경우 전문가조차도 어떤 장벽이 필요한지 정확히 동의 할 수는 없습니다. 전문가가 옳고 그른 것이 무엇인지 동의하지 않는 상황을 피하려고 노력하는 경향이 있습니다!

저자는 이중 잠금이 다른 전략보다 효과가 적으므로 사용해서는 안된다는 것을 암시하는 것 같습니다.

다른 팁

Double-Checking Locking은 이제 Java와 C#에서 작동합니다 (Java 메모리 모델이 변경되었으며 이것이 효과 중 하나입니다). 그러나, 당신은 그것을 받아야합니다 바로 그거죠 오른쪽. 일을 약간 엉망으로 만들면 스레드 안전을 잃게 될 수 있습니다.

다른 답변이 언급 한 바와 같이, 당신이 구현하는 경우 싱글 톤 패턴 더 좋은 방법이 있습니다. 개인적으로, 두 번 확인 된 잠금 장치와 "잠금"코드 중에서 선택 해야하는 상황에 처한 경우 병목 현상이 발생한다는 실제 증거를 얻을 때까지 매번 잠금을 시작합니다. 스레딩에 관해서는 간단하고 명백히 수정 된 패턴이 많이 가치가 있습니다.

.NET 4.0에는 새로운 유형이 있습니다. Lazy<T> 그것은 패턴을 잘못 이해하는 것에 대한 우려를 빼앗아갑니다. 새로운 작업 병렬 라이브러리의 일부입니다.

MSDN 병렬 컴퓨팅 개발 센터를 참조하십시오. http://msdn.microsoft.com/en-us/concurrency/default.aspx

BTW, .NET 3.5 SP1 용 백 포트가 있습니다 (지원되지 않음). 여기.

Java (및 .NET에서도 가장 가능성이 높음)보다 싱글 톤 초기화를위한 이중 체크 잠금은 완전히 불필요하고 깨진 것입니다. 클래스는 처음으로 사용될 때까지 초기화되지 않기 때문에 원하는 게으른 초기화는 이미 이에 의해 달성되었습니다.

private static Singleton instance = new Singleton();

싱글 톤 클래스에 싱글 톤 인스턴스가 처음 사용되기 전에 액세스 할 수있는 상수와 같은 것들이 포함되어 있지 않으면 이것이 필요한 모든 것입니다.

모든 사람들이 이중 확인 잠금이 나쁜 패턴이라고 말하는 이유는 없지만 코드를 올바르게 작동 시키도록 코드를 조정하지는 않습니다. 제 생각에는 아래 코드는 잘 작동합니다.

이 코드가 Cameron의 기사에 언급 된 문제로 고통받는 지 말해 줄 수 있다면하십시오.

public sealed class Singleton {
    static Singleton instance = null;
    static readonly object padlock = new object();

    Singleton() {
    }

    public static Singleton Instance {
        get {
            if (instance != null) {
                return instance;
            }

            lock (padlock) {
                if (instance != null) {
                    return instance;
                }

                tempInstance = new Singleton();

                // initialize the object with data

                instance = tempInstance;
            }
            return instance;
        }
    }
}

부울을 사용하여 작업하기 위해 두 번 확인 된 잠금을 얻었습니다 (즉, 게으른 초기화를 피하기 위해 원시를 사용하여) :

부울을 사용하는 싱글 톤은 작동하지 않습니다. 메모리 장벽을 거치지 않는 한 다른 스레드간에 보이는 작동 순서는 보장되지 않습니다. 다시 말해, 두 번째 스레드에서 볼 수 있듯이created = true 전에 실행 될 수 있습니다 instance= new Singleton();

나는 왜 이중 체크 잠금에 구현 패턴이 왜 있는지 잘 모르겠습니다 (다양한 언어로 컴파일러 특유의 일을 제외하고). 이 주제에 대한 Wikipedia 기사는 순진한 방법과 문제를 해결할 수있는 가능한 방법을 보여줍니다. 그러나 C#에서 이것만큼 간단한 것은 없습니다.

public class Foo
{
  static Foo _singleton = null;
  static object _singletonLock = new object();

  public static Foo Singleton
  {
    get
    {
      if ( _singleton == null )
        lock ( _singletonLock )
          if ( _singleton == null )
          {
            Foo foo = new Foo();

            // Do possibly lengthy initialization,
            // but make sure the initialization
            // chain doesn't invoke Foo.Singleton.
            foo.Initialize();

            // _singleton remains null until
            // object construction is done.
            _singleton = foo;
          }
      return _singleton;
    }
  }

Java에서는 lock () 대신 Synchronized ()를 사용하지만 기본적으로 동일한 아이디어입니다. 싱글 톤 필드가 할당 된 시점의 불일치가있는 경우, 먼저 로컬 스코핑 변수를 먼저 사용한 다음 중요한 섹션을 종료하기 전에 가능한 마지막 순간에 싱글 톤 필드를 할당하지 않겠습니까? 내가 뭔가를 놓치고 있습니까?

@Michael-Borgwardt의 C#과 Java에서 정적 필드는 처음 사용하면 한 번만 초기화되지만 논쟁이 있습니다. 저것 행동은 언어에 따라 다릅니다. 그리고 컬렉션 속성의 게으른 초기화 (예 : user.sessions) 에이 패턴을 자주 사용했습니다.

부울을 사용하여 작업하기 위해 두 번 확인 된 잠금을 얻었습니다 (즉, 게으른 초기화를 피하기 위해 원시를 사용하여) :

private static Singleton instance;
private static boolean created;
public static Singleton getInstance() {
    if (!created) {
        synchronized (Singleton.class) {
            if (!created) {
                instance = new Singleton();
                created = true;
            }
        }
    }
    return instance;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top