DEV Community

Java Efetivo (livro)
Java Efetivo (livro)

Posted on

79: Evite a Sincronização Excessiva

Perigos da Sincronização Excessiva:

  • Redução de desempenho.
  • Conflitos.
  • Comportamento não determinístico.

Evitar Transferência de Controle:

  • Não invocar métodos desconhecidos (projetados para serem sobrescritos ou fornecidos pelo cliente) dentro de blocos sincronizados.
  • Chamadas desconhecidas podem causar:
  • Exceções.
  • Deadlocks.
  • Corrupção de dados.

Exemplo: Classe ObservableSet:

  • Implementa um padrão de observador, notificando sobre elementos adicionados ao conjunto.
  • Problema: Invocar métodos de observadores dentro de blocos sincronizados causa exceções (ex.: ConcurrentModificationException) e deadlocks.

Problemas e Soluções:
- Exceções:

  • Ocorrência: Modificar a lista de observadores enquanto itera sobre ela.
  • Solução: Deslocar invocações para fora dos blocos sincronizados.

Deadlocks:
Ocorrência: Threads bloqueiam recursos mutuamente.
Solução: Evitar bloqueios reentrantes desnecessários.

Uso de Coleções Concorretes:

  • Substituir listas sincronizadas por CopyOnWriteArrayList.
  • Evita bloqueios durante iterações, ideal para listas raramente modificadas.

Boas Práticas:

  • Minimize operações em blocos sincronizados.
  • Faça apenas o essencial (examine/modifique dados compartilhados).
  • Realize operações demoradas fora dos blocos sincronizados.

Impacto no Desempenho:

  • Contenção reduz oportunidades de paralelismo.
  • Limita otimizações da JVM.

Abordagens para Sincronização:

  • Omita sincronização interna e permita que o cliente sincronize.
  • Sincronize internamente apenas se conseguir alta concorrência.
  • Exemplo: StringBuilder (não sincronizado) substituiu StringBuffer (sincronizado).

Sincronização de Campos Estáticos:

  • Sincronize modificações internas se métodos puderem ser chamados por várias threads.
  • Campos estáticos compartilham estado global.

Conclusão:

  • Evite deadlocks e falhas de segurança deslocando chamadas desconhecidas para fora de blocos sincronizados.
  • Documente explicitamente a thread-safety da classe.

Exemplos de Código
1. Classe ObservableSet com Problema de Exceção

public class ObservableSet<E> {
    private final Set<E> set = new HashSet<>();
    private final List<SetObserver<E>> observers = new ArrayList<>();

    public synchronized void addObserver(SetObserver<E> observer) {
        observers.add(observer);
    }

    public synchronized void removeObserver(SetObserver<E> observer) {
        observers.remove(observer);
    }

    public synchronized boolean add(E element) {
        boolean added = set.add(element);
        if (added) notifyElementAdded(element);
        return added;
    }

    private void notifyElementAdded(E element) {
        for (SetObserver<E> observer : observers) {
            observer.added(this, element);
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

2. Corrigindo o Problema com CopyOnWriteArrayList

import java.util.concurrent.CopyOnWriteArrayList;

public class ObservableSet<E> {
    private final Set<E> set = new HashSet<>();
    private final CopyOnWriteArrayList<SetObserver<E>> observers = new CopyOnWriteArrayList<>();

    public void addObserver(SetObserver<E> observer) {
        observers.add(observer);
    }

    public void removeObserver(SetObserver<E> observer) {
        observers.remove(observer);
    }

    public boolean add(E element) {
        boolean added = set.add(element);
        if (added) notifyElementAdded(element);
        return added;
    }

    private void notifyElementAdded(E element) {
        for (SetObserver<E> observer : observers) {
            observer.added(this, element);
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

3. Exemplo de Deadlock (a ser evitado)

executor.execute(() -> {
    s.removeObserver(this); // Deadlock ao tentar remover durante bloqueio
});

Enter fullscreen mode Exit fullscreen mode

4. Boas Práticas para Sincronização

public synchronized void performOperation() {
    // Operação essencial dentro do bloco sincronizado
    sharedData.modify();

    // Operação demorada fora do bloco sincronizado
    processUnsharedData();
}

Enter fullscreen mode Exit fullscreen mode

exemplos do livro

Image description

Image description

Image description

Image description

Image description

Image description

Image description

Top comments (0)