# 13 problemas de concorrência em aplicação que quebram seu sistema

> Os 13 problemas de concorrência em aplicação causam travamentos, perda de dados e lentidão sob carga. Condições de corrida, deadlocks, starvation e inconsistências de cache estão entre as falhas críticas. Identificar cada cenário exige análise de sincronização, atomicidade e visibilidade de memória. Soluções envolvem locks, transações otimistas e filas. A correção preventiva reduz falhas em produção.

*Blog Sem Juízo · Destaques · 28 de agosto de 2026 · Babi Cordeiro*

Sua aplicação trava, perde dados ou fica lenta sob carga? Esses 13 problemas de concorrência explicam o porquê. Veja como identificar e resolver cada um.

Senta que lá vem história: sua aplicação funcionava linda com 10 usuários, mas no lançamento ela travou, perdeu pedidos e deixou todo mundo bravo. A culpa, quase sempre, é da concorrência. Quando várias requisições acessam o mesmo recurso ao mesmo tempo, sem controle, o caos se instala. Neste guia, nós vamos passear pelos 13 problemas de concorrência mais comuns em aplicações, do mais crítico ao mais sutil, com exemplos práticos para você reconhecer cada um antes que eles quebrem seu sistema.

## 1. Corrida (race condition)

A corrida acontece quando duas ou mais threads leem e escrevem o mesmo dado sem sincronização. O resultado depende da ordem de execução, que é imprevisível. Um exemplo clássico: dois usuários clicam em "comprar" ao mesmo tempo, e o estoque vai de 1 para -1. O critério para identificar: se o comportamento muda conforme a carga ou a ordem de chegada, você tem uma corrida.

## 2. Deadlock

Deadlock é o impasse em que duas threads esperam uma pela outra para liberar recursos, e nenhuma avança. Imagine a thread A segura o recurso X e espera o Y, enquanto a thread B segura o Y e espera o X. As duas ficam presas para sempre. Um sinal claro: a aplicação congela de vez em quando, sem erro aparente, e só resolve com reinício.

## 3. Starvation

Starvation é quando uma thread nunca consegue acesso a um recurso porque outras threads sempre passam na frente. Isso acontece com políticas de prioridade mal configuradas. Na prática, algumas requisições ficam eternamente na fila, enquanto outras são atendidas. O usuário vê timeout, mas o servidor está ocupado.

## 4. Perda de atualização (lost update)

Duas threads leem o mesmo valor, cada uma modifica com base nesse valor, e a última a escrever sobrescreve a primeira. Exemplo: dois editores atualizam o mesmo artigo, e a versão do segundo apaga as mudanças do primeiro sem querer. O problema é silencioso: ninguém recebe erro, mas o dado some.

## 5. Leitura suja (dirty read)

Uma thread lê um dado que outra thread ainda não confirmou (commit). Se a segunda thread fizer rollback, a primeira usou uma informação que nunca existiu oficialmente. Isso é comum em bancos com isolamento baixo. O resultado: decisões erradas baseadas em dados fantasma.

## 6. Isolamento inadequado

Quando o nível de isolamento do banco é muito baixo, transações enxergam mudanças não confirmadas de outras. Isso abre portas para leituras sujas, leituras não repetíveis e phantom reads. O critério: se duas transações simultâneas produzem resultados diferentes para a mesma consulta, o isolamento está frouxo.

## 7. Contenção de lock

Muitas threads disputando o mesmo lock fazem a aplicação ficar lenta, mesmo com CPU ociosa. O lock vira um gargalo. Por exemplo, um lock global em uma tabela de configuração derruba a performance quando o número de usuários cresce. O sintoma: latência aumenta de forma desproporcional com o número de requisições.

## 8. Condição de corrida em cache

Cache é ótimo, mas quando duas threads atualizam o mesmo cache ao mesmo tempo, uma pode sobrescrever a outra com dados velhos. Ou pior: uma thread lê o cache enquanto outra o invalida. O resultado é inconsistência temporária. Um exemplo: um preço exibido errado por alguns segundos, depois corrigido.

## 9. Sobrecarga de threads

Criar uma thread por requisição parece simples, mas cada thread consome memória e contexto de troca. Com milhares de requisições, o sistema gasta mais tempo trocando de thread do que processando. O sintoma: uso de CPU alto, mas throughput baixo. A solução passa por pools de threads ou programação assíncrona.

## 10. Escalabilidade limitada

Concorrência mal feita limita a escalabilidade horizontal. Se você usa locks distribuídos ou estado compartilhado em memória, adicionar mais servidores não ajuda, só piora a contenção. O critério: ao dobrar as instâncias, a performance não melhora, ou até piora.

## 11. Dificuldade de debug

Erros de concorrência são intermitentes e difíceis de reproduzir. Eles aparecem só sob carga, em horários específicos, e somem quando você adiciona logs. Isso transforma cada bug em uma investigação longa. O custo não é só técnico, é emocional. Uma ressalva: ferramentas de detecção de corrida ajudam, mas não pegam tudo.

## 12. Complexidade de código

Sincronizar tudo com locks, semáforos e monitores deixa o código difícil de ler e manter. Cada bloqueio é um ponto de erro. E o pior: a complexidade esconde bugs. Um exemplo: um desenvolvedor novo adiciona um lock para resolver um bug e cria um deadlock em outro lugar.

## 13. Inconsistência de dados em geral

No fim, todos os problemas anteriores se resumem a dados inconsistentes. Uma aplicação concorrente sem controle pode gerar valores errados, duplicatas, ou perda de informações. O critério de aceite para qualquer sistema concorrente: os dados permanecem íntegros mesmo com milhares de requisições simultâneas.

## Como escolher a abordagem certa

Para a maioria das aplicações web, comece com transações de banco com isolamento adequado e evite estado compartilhado. Se precisar de mais performance, considere filas e processamento assíncrono. Para sistemas críticos, estude padrões como optimistic locking ou versionamento de dados. E nunca confie em "funciona na minha máquina": teste com carga real.

## FAQ

### O que é concorrência em uma aplicação?

Concorrência é a capacidade de uma aplicação executar várias tarefas ao mesmo tempo, seja com threads, processos ou operações assíncronas. Ela é essencial para performance, mas exige controle para evitar conflitos entre requisições que acessam os mesmos recursos.

### Qual a diferença entre concorrência e paralelismo?

Concorrência é sobre lidar com várias tarefas ao mesmo tempo, mas não necessariamente executá-las simultaneamente. Paralelismo é executar de fato várias tarefas ao mesmo tempo, usando múltiplos núcleos de CPU. Uma aplicação concorrente pode ser paralela ou não.

### Como identificar uma race condition?

O sinal clássico é um comportamento intermitente que só aparece sob carga ou quando várias requisições chegam juntas. Para confirmar, use ferramentas de detecção de corrida (como race detector do Go ou ThreadSanitizer) e teste com estresse controlado.

### O que é deadlock e como evitar?

Deadlock é quando duas threads ficam esperando uma pela outra para liberar recursos, travando o sistema. Para evitar, estabeleça uma ordem global para aquisição de locks, use timeouts e evite locks aninhados sempre que possível.

### O que é isolamento em banco de dados?

Isolamento é o nível de separação entre transações simultâneas. Ele define o que uma transação pode ver de outra. Níveis mais altos, como SERIALIZABLE, evitam problemas, mas reduzem performance. O ideal é equilibrar consistência e velocidade.

### Como testar problemas de concorrência?

Use testes de carga com ferramentas como JMeter ou k6, simulando muitos usuários simultâneos. Além disso, escreva testes específicos que disparam várias threads ao mesmo tempo em um mesmo recurso. E monitore logs e métricas para detectar anomalias.

---

Fonte (canonical): https://blogsemjuizo.com.br/destaques/13-problemas-de-concorrencia-em-aplicacao-que-quebram-seu-sistema/
