Pergunta

Quando um campo de classe é acessado através de um método getter por vários segmentos, como você manter a segurança do thread? É a palavra-chave sincronizado suficiente?

É seguro:

public class SomeClass {
    private int val;

    public synchronized int getVal() {
        return val;
    }

    private void setVal(int val) {
        this.val = val;
    }
}

ou não o setter introduzir outras complicações?

Foi útil?

Solução

Se você usar 'sincronizado' no setter, também aqui, este código é threadsafe. No entanto, pode não ser suficientemente granular; Se você tem 20 getters e setters e eles estão todos sincronizados, você pode estar criando um gargalo de sincronização.

Neste caso específico, com uma única variável int, em seguida, eliminando o 'sincronizado' e marcando o campo int 'volátil' também irá garantir visibilidade (cada segmento vai ver o último valor de 'val' ao chamar o getter), mas não pode ser sincronizado o suficiente para suas necessidades. Por exemplo, espera

 int old = someThing.getVal();
 if (old == 1) {
    someThing.setVal(2);
 }

para definir val a 2, se e somente se ele já está 1 está incorreto. Para isso, você precisa de um bloqueio externo, ou algum método de comparar-e-set atômica.

Eu sugiro fortemente que você leia Java Concurrency in Practice por Brian Goetz et al , que tem a melhor cobertura de construções de simultaneidade de Java.

Outras dicas

Além de Cowan comentário , você pode fazer o seguinte para uma loja de comparar e:

synchronized(someThing) {
    int old = someThing.getVal();
    if (old == 1) {
        someThing.setVal(2);
    }
}

Isso funciona porque o bloqueio definido por meio de um método sincronizado é implicitamente o mesmo bloqueio do objeto ( ver a linguagem java especificação ).

No meu entendimento você deve usar sincronizados em ambos os getter e dos métodos setter, e isso é suficiente.

Edit: Aqui é um ligação para mais algumas informações sobre a sincronização e quais não.

Se a sua classe contém apenas uma variável, em seguida, uma outra maneira de alcançar thread-segurança é usar o objeto AtomicInteger existente.

public class ThreadSafeSomeClass {

    private final AtomicInteger value = new AtomicInteger(0);

    public void setValue(int x){
         value.set(x);
    }

    public int getValue(){
         return value.get();
    }

}

No entanto, se você adicionar variáveis ??adicionais de tal forma que eles são dependentes (estado de uma variável depende do estado de outro), então AtomicInteger não vai funcionar.

Repetindo a sugestão de ler "Java Concurrency in Practice".

Para objetos simples, isto pode ser suficiente. Na maioria dos casos você deve evitar a palavra-chave sincronizado, porque você pode se deparar com um bloqueio de sincronização.

Exemplo:

public class SomeClass {

  private Object mutex = new Object();
  private int    val   = -1; // TODO: Adjust initialization to a reasonable start
                             //       value
  public int getVal() {
    synchronized ( mutex ) {
      return val;
    }
  }

  private void setVal( int val ) {
    synchronized ( mutex ) {
      this.val = val;
    }
  }
}

assegura que apenas uma thread lê ou escreve o membro de instância local.

Leia o livro "Programação Concorrente em Java (TM): Princípios de Design e Padrões (Java (Addison-Wesley))", talvez http://java.sun.com/docs/books/tutorial/essential/concurrency/index.html também é útil ...

Sincronização existe para proteger contra interferências fio e erros de consistência de memória. Ao sincronizar na getVal (), o código é garantir que outros métodos sincronizados em SomeClass também não executar ao mesmo tempo. Como não existem outros métodos sincronizados, não está fornecendo muito valor. Observe também que lê e escreve sobre primitivas têm acesso atômica. Isso significa que com programação cuidadosa, não é necessário para sincronizar o acesso ao campo.

Leia sychronization .

Na verdade, não sei por que isso foi caiu para -3. Estou simplesmente resumindo o que o tutorial Sincronização de Sun diz (assim como minha própria experiência).

Usando o simples acesso variável atômica é mais eficiente do que o acesso destes variáveis ??por meio de código sincronizado, mas requer mais cuidado pela programador consistência de memória evitar erros. Se o esforço extra é vale a pena depende do tamanho e complexidade da aplicação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top