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
}
}
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
* }
* }
*/
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
}
}
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)