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

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay