Pergunta

Eu vim através deste discutindo por que o dobro -verificar bloqueio paradigma é quebrado em Java. É o paradigma válido para .NET (em particular, C #), se as variáveis ??são declaradas volatile?

Foi útil?

Solução

implementar o padrão Singleton em negociações C # sobre este problema na terceira versão.

Ele diz:

Fazendo a variável de instância volátil pode fazê-lo funcionar, como seria chamadas de barreira memória explícita, embora neste último caso até mesmo especialistas não conseguem concordar exatamente qual as barreiras são necessárias. I tendem a tentar situações Evitar onde especialistas não concordam que é certo eo que é errado!

O autor parece implicar que bloqueio duplo é menos provável de trabalho do que outras estratégias e, portanto, não deve ser utilizado.

Outras dicas

duplo controlo bloqueio agora trabalha em Java, bem como C # (o modelo de memória Java mudou e este é um dos efeitos). No entanto, você tem que obtê-lo exatamente direita. Se você bagunçar as coisas mesmo que ligeiramente, você pode muito bem acabar por perder a segurança do thread.

Como outras respostas afirmaram, se você está implementando o href="http://pobox.com/~skeet/csharp/singleton.html" rel="noreferrer"> singleton padrão lá são muito melhores maneiras de fazer isso. Pessoalmente, se eu estou em uma situação onde eu tenho que escolher entre bloqueio duplo verificado e "bloquear sempre" código de eu ir para o bloqueio cada vez que até eu tenho evidência real de que ele estava causando um gargalo. Quando se trata de threading, um simples e obviamente correto padrão vale muito.

.NET 4.0 tem um novo tipo: Lazy<T> que tira qualquer preocupação sobre como obter o errado padrão. É parte da nova biblioteca paralela de tarefas.

Veja o MSDN computação paralela Dev Center: http://msdn.microsoft. com / en-us / simultaneidade / default.aspx

BTW, há um backport (creio que não é suportado) para .NET 3.5 SP1 disponível aqui .

Note que em Java (e, provavelmente, na Net também), com verificação dupla de bloqueio para inicialização singleton é completamente desnecessário, bem como quebrado. Como as classes não são inicializados até que eles são utilizados pela primeira vez, a inicialização lenta desejada já esteja garantido por este;

private static Singleton instance = new Singleton();

A menos que sua classe Singleton contém coisas como constantes que podem ser acessados ??antes de uma instância Singleton é utilizado pela primeira vez, isso é tudo que você precisa fazer.

Eu não entendo por que todas as pessoas diz que o bloqueio duplo-check é ruim padrão, mas não adaptar o código para que ele funcione corretamente. Na minha opinião, este código abaixo deve funcionar muito bem.

Se alguém poderia me dizer se este código sofrem com o problema mencionada no artigo de Cameron, por favor.

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;
        }
    }
}

Eu comecei com verificação dupla de bloqueio para o trabalho usando um boolean (ou seja, usando um primitivo para evitar a inicialização preguiçoso):

O singleton usando boolean não funciona. A ordem das operações, como visto entre os diferentes tópicos não é garantida a menos que você passar por uma barreira de memória. Em outras palavras, como visto de um segundo segmento, created = true pode ser executado antes instance= new Singleton();

Eu não entendo muito bem porque há um monte de padrões de implementação de bloqueio com verificação dupla (aparentemente para trabalho em torno de idiossincrasias do compilador em várias línguas). O artigo da Wikipedia sobre este tópico mostra o método ingênuo e as possíveis maneiras de resolver o problema, mas nenhum é tão simples como isto (em 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;
    }
  }

Em Java, você pode usar sincronizado () em vez de bloqueio (), mas é basicamente a mesma idéia. Se há a possível inconsistência quando o campo singleton é atribuído, então por que não usar uma variável com escopo localmente em primeiro lugar e, em seguida, atribuir o campo singleton no último momento possível antes de sair da seção crítica? Estou faltando alguma coisa?

Há o argumento @ michael-Borgwardt que em C # e Java do campo estático só é inicializado uma vez no primeiro uso, mas que comportamento é específico da linguagem. E eu usei esse padrão com freqüência para a inicialização lenta de uma propriedade de coleção (por exemplo user.Sessions).

Eu comecei com verificação dupla de bloqueio para o trabalho usando um boolean (ou seja, usando um primitivo para evitar a inicialização preguiçoso):

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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top