Pergunta

private static Callback callback;

public Foo()
{
    super(getCallback());
}

private static Callback getCallback()
{
    callback = new Callback();
    return callback;
}

Construtor Foo () pode, potencialmente, ser chamado de vários segmentos. Minha preocupação é com o campo estático privado 'callback' e o método estático 'getCallback ()'.

Como pode ser visto, cada vez 'getCallback ()' é chamado, ele atribui um novo valor para o campo 'callback' estática.

Meu palpite é que não é thread-safe, porque a palavra-chave estática está sempre ligado à classe não a instância, o que significa, o campo estático 'callback' de um Foo pode, potencialmente, ser substituído por outro fio que está a construir um outro Foo (). É este correto?

Por favor me corrija se eu estiver errado. Obrigado!

EDIT: Minha intenção é manter em algum lugar 'callback' na classe, para que eu possa reutilizá-lo mais tarde. Mas isso não é fácil, porque Foo se estende a partir de uma classe que tem construtor obrigatoriedade 'callback' para ser transmitida.

Foi útil?

Solução

Sim, você está correto. É possível que duas instâncias de Foo para acabar com a mesma instância CallBack quando dois threads introduzir o método getCallback() simultaneamente e se atribui um novo CallBack ao campo estático enquanto o outro já fez isso, mas ainda não retornaram. Neste caso, a melhor solução é não ter o campo estático, uma vez que não serve para nada. Alternativamente, make getCallback() sincronizado.

Mas note que é não verdade que apenas os static resultados de palavras-código que não é threadsafe.

Outras dicas

Não é thread-safe. Experimente estas alternativas:

Opção 1: aqui todas as instâncias compartilham o mesmo callback

private static final Callback callback = new Callback();

public Foo() {
    super(callback);
}

Opção 2: aqui cada instância tem seu próprio callback

public Foo() {
    super(new Callback());
}

Note que em ambos os casos, embora o construtor é thread-safe, o thread-segurança de toda a classe depende da implementação de retorno de chamada. Se ele tem estado mutável, então você vai ter problemas potenciais. Se Callback é imutável, então você tem thread-segurança.

Callback vai ter um novo valor de cada Foo time () é chamado (mesmo a partir do mesmo segmento). Eu não tenho certeza do que seu código deve estar fazendo (se você quiser inicializar a variável estática apenas uma vez (singleton), você deve verificar se ele ainda é nulo em getCallback (?) - e o que é actionCallback). Para tornando-thread-safe, o uso sincronizado.

Eu acho que você resumiu perfeitamente a si mesmo, mas sem mais detalhes sobre o que você está tentando conseguir que vai ser difícil de fazer sugestões para corrigir o problema.

Uma pergunta óbvia é, não callback tem que ser estático? Ou você pode com segurança torná-lo um campo de instância sem quebrar a funcionalidade de sua classe?

Eu sei que foi respondida, mas o por que realmente não foi detalhado.

dois tópicos estão chamando o método getCallback (), eles poderiam executar as linhas da seguinte forma:

  1. Thread 1 - callback = new Callback ();
  2. Thread 2 - callback = new Callback ();
  3. Passe 1 - retorno actionCallback;
  4. Passe 2 - retorno actionCallback;

Neste caso, o retorno gerado pelo (2.) seria devolvido em ambos (3) e (4).

A solução parece ser a perguntar por que retorno de chamada definido staticly se ele é específico para a instância não classe.

Espero que ajuda.

O que você está tentando fazer é chamado um padrão Singleton, se você fizer uma pesquisa você pode descobrir por que sua geralmente uma boa idéia para evitar este padrão se você pode, no entanto, se você precisar dele você pode fazer o seguinte.

private static final Callback CALLBACK= new Callback();

Ou se você precisa de um Singleton preguiçoso você pode fazer

public class Foo {
   class CallbackHolder {
       static final Callback CALLBACK= new Callback();
   }

   public static Callback getCallback() {
      return CallbackHolder.CALLBACK;
   }

public Foo() {
    super(getCallback());
}

Ambas as implementações são thread-safe.

Você quer um retorno de chamada por thread, um por objeto, ou um verdadeiro Singleton?

Alguns esboços de como fazer as diferentes variantes - apenas a partir do topo da minha cabeça, não tome estas também literalmente:)

Por favor note que eu tenho assumido que o retorno de chamada tem um construtor não-trivial que pode lançar exceção que precisa ser tratada, se é um construtor trivial você pode simplificar tudo isso muito.

Um por thread:

  private static ThreadLocal<Callback> callback;

  public Foo()
  {
      super(getCallback());
  }

  private static Callback getCallback()
  {
      if ( callback.get() == null ) 
          callback.set(new Callback());
      return callback.get();
  }

callback único para os tópicos:

  private final static Callback callback;

  static {
      callback = new Callback(); 
  }

  public Foo()
  {
      super(getCallback());
  }

  private static Callback getCallback()
  {
      return callback;
  }

E, por completitude, um retorno de chamada por objeto:

  private Callback callback;

  public Foo()
  {
      super(getCallback());
  }

  private Callback getCallback()
  {
      callback = new Callback();
      return callback;
  }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top