DEV Community

Java Efetivo (livro)
Java Efetivo (livro)

Posted on

Item 82: Documente a thread safety

Importância de documentar a thread safety

  • Parte do contrato da classe: A forma como uma classe lida com acesso concorrente é crucial para seus clientes.

Riscos de suposições erradas:

  • Sincronização deficiente ou excessiva (Itens 78 e 79).
  • Erros graves no comportamento do programa.

Problemas com o uso de synchronized como indicador

  • Detalhe de implementação: Não é parte da API pública.
  • Visão simplista: Thread safety não é uma propriedade binária (tudo ou nada); há níveis diferentes.

Níveis de thread safety
Imutável:

  • Comportam-se como constantes.
  • Não necessitam de sincronização externa.
  • Exemplos: String, Long, BigInteger.

Incondicionalmente thread-safe:

  • Instâncias mutáveis, mas com sincronização interna suficiente.
  • Uso concorrente seguro sem sincronização adicional.
  • Exemplos: AtomicLong, ConcurrentHashMap.

Condicionalmente thread-safe:

  • Similar ao incondicional, mas alguns métodos requerem sincronização externa.
  • Exemplo: Coleções de Collections.synchronized, que exigem sincronização ao iterar:
Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>());
synchronized (syncMap) {
    for (String key : syncMap.keySet()) {
        // Iteração segura
    }
}

Enter fullscreen mode Exit fullscreen mode

Sem thread safety:

  • Necessário envolver métodos com sincronização externa.
  • Exemplos: ArrayList, HashMap.

Hostil à thread:

  • Não são seguras mesmo com sincronização externa.
  • Geralmente resultado de erros, como modificação de dados estáticos sem sincronização.

Como documentar a thread safety
Documentação clara no Javadoc:

  • Nível de segurança oferecido.
  • Métodos ou sequências que requerem sincronização externa.
  • Bloqueios específicos a serem usados.

Exemplo de documentação de sincronização para iteração:

/**
 * É necessário sincronizar manualmente ao iterar sobre as views deste mapa.
 * Exemplo:
 * synchronized (map) {
 *     for (Object key : map.keySet()) {
 *         // Iteração segura
 *     }
 * }
 */

Enter fullscreen mode Exit fullscreen mode

Uso de objeto de bloqueio privado
Vantagens:

  • Evita interferência de clientes e subclasses.
  • Permite controle de concorrência mais sofisticado no futuro.

Exemplo:

private final Object lock = new Object();

public void threadSafeMethod() {
    synchronized (lock) {
        // Código protegido
    }
}

Enter fullscreen mode Exit fullscreen mode

Campos final: Protegem contra alterações acidentais no objeto de bloqueio.

Cuidados ao projetar classes para herança

  • Usar o mesmo bloqueio em subclasse e classe base pode causar interferências.
  • Preferir o bloqueio privado para evitar conflitos.

Resumo final

  • Documente sempre a thread safety de uma classe (com texto ou anotações).
  • Não confie apenas no modificador synchronized para documentar.
  • Para classes incondicionalmente thread-safe, considere usar objetos de bloqueio privados.
  • Classes condicionalmente thread-safe devem especificar quais bloqueios usar e quando.

Top comments (0)