Conhecimento de entrevista, como a autoapresentação de um minuto
“Qual é a diferença entre processo e thread?”
Na época em que eu me preparava para conseguir o primeiro emprego, essa pergunta estava sempre no “TOP 10 das perguntas mais comuns em entrevistas”. Eu respondia como uma máquina:
“Um processo é um programa em execução, e uma thread é uma unidade de fluxo que roda dentro de um processo. Os processos não compartilham recursos, mas as threads compartilham.”
O entrevistador assentia com a cabeça, e eu me iludia achando que tinha entendido o conceito perfeitamente. Mas, até dar de cara com “problemas de concorrência” (concurrency issues) no trabalho real, eu não fazia a menor ideia do perigo de verdade escondido naquela frase.
“Por que o contador de visualizações deveria subir 100 e só sobe 98?” “Por que o site trava quando alguém dispara um download de Excel?”
Meu código era perfeito quando eu o rodava sozinho, mas, assim que vários usuários entraram ao mesmo tempo, virou uma bagunça. Eu achava que bastava aumentar o número de “trabalhadores”, mas não sabia que, quanto mais trabalhadores, mais o custo de gerenciá-los (context switching) cresce exponencialmente.

As fábricas e os trabalhadores do centro logístico digital
Vamos voltar ao universo do nosso “centro logístico digital”. Um programa rodar dentro do computador é como montar uma “oficina” (factory) dentro do centro logístico.
1. Processo (Process): uma oficina independente
- Definição: uma “unidade de trabalho independente” que recebe recursos do sistema operacional (o gerente da fábrica).
- Característica: cada um tem o seu próprio prédio. Mesmo que a fábrica vizinha desabe (erro), a minha continua segura.
- Custo: para construir uma fábrica, você precisa de terreno (memória) e também de registrar a empresa (PID). “É caro e pesado.”
- Compartilhamento: em princípio, não dá para pegar as coisas da fábrica vizinha. (É preciso usar uma comunicação complicada chamada IPC.)
2. Thread: os operários dentro da oficina
- Definição: o “trabalhador” que de fato executa o trabalho dentro do processo (a oficina).
- Característica: uma única fábrica pode ter vários operários (multithread).
- Custo: contratar um operário novo é muito mais “barato e leve” do que construir uma fábrica nova.
- Compartilhamento: este é o ponto-chave. Os operários dividem “o refeitório (Heap) e a sala de descanso (Data)”.

[Code Verification] A tragédia do compartilhamento (problemas de concorrência)
“As threads compartilham recursos.” Na entrevista, essa frase soava como uma vantagem, mas, no trabalho real, pode ser a semente de uma “catástrofe”.
Você se lembra da “heap” que vimos da última vez? As threads compartilham essa área da heap. Ou seja, a thread B pode chegar e sobrescrever os dados com que a thread A está trabalhando.
Isso se chama “condição de corrida” (race condition). Vamos conferir no código.
public class RaceConditionTest {
static int count = 0; // Variável compartilhada armazenada na heap
public static void main(String[] args) throws InterruptedException {
// Contratando dois trabalhadores (threads)
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) count++;
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) count++;
});
t1.start(); // Mãos à obra!
t2.start(); // Mãos à obra!
t1.join(); // Espera até o fim do expediente
t2.join(); // Espera até o fim do expediente
System.out.println("Resultado final: " + count);
}
}
Resultado esperado: como dois trabalhadores somaram 10.000 vezes cada um, o resultado deveria ser 20,000.
Resultado real: 15,482, 18,931… O valor muda a cada execução e nunca chega a 20.000.
Motivo:
- A thread A lê
count(100)da heap e o leva para a sua stack. - Nesse meio-tempo, a thread B também lê
count(100)da heap. - A thread A aumenta o valor para 101 e grava na heap.
- A thread B (como o que ela leu era 100) também aumenta o valor para 101 e grava na heap.
- Foram duas somas, mas o resultado equivale a uma só.
Essa é a verdadeira identidade do bug de “às vezes os dados somem” que aparece no trabalho real. É a tragédia de trabalhadores mexendo no mesmo livro-caixa sem conversar entre si.
Fazendo uma analogia com banco de dados (BD), é exatamente igual à situação de “várias consultas disparadas ao mesmo tempo sem transação”. Como o saldo da conta é alterado simultaneamente sem nenhum mecanismo de proteção (lock), acontece um acidente terrível: o dinheiro evapora. Assim como protegemos os dados no banco com ROLLBACK ou COMMIT, no nível do código também precisamos, sem falta, de um mecanismo de bloqueio como Synchronized.
O trade-off na prática: multiprocesso vs. multithread
Então, no trabalho real, o que devemos usar, e quando?
1. A escolha do navegador Chrome: multiprocesso
No antigo Internet Explorer, se uma aba travava, o navegador inteiro fechava (modelo multithread). Já o Chrome abre cada aba como um “processo separado” (uma fábrica própria).
- Vantagem: mesmo que uma aba pare de responder (mesmo que a fábrica exploda), as outras abas (as fábricas vizinhas) continuam intactas. (Estabilidade)
- Desvantagem: consome uma quantidade enorme de memória. É por isso que o Chrome ganhou fama de “devorador de RAM”. (Custo)
2. A escolha dos servidores web (Spring, Node.js etc.): multithread
Um servidor precisa processar as requisições de milhares de pessoas. Se ele construísse um processo (uma fábrica) para cada requisição, explodiria. Por isso, coloca inúmeras threads (operários) dentro de um único processo para dar conta delas.
- Vantagem: usa poucos recursos e é rápido. (Eficiência)
- Desvantagem: se uma única thread gera um erro que derruba o processo, o servidor inteiro cai. Além disso, o próprio desenvolvedor precisa impedir os problemas de concorrência que vimos há pouco (Synchronized).

Para encerrar: a técnica dos clones das sombras traz responsabilidades
Hoje vimos “processos e threads”, o jeito como os nossos operários trabalham.
- Processo: uma oficina independente, segura, mas cara.
- Thread: um colega de trabalho leve e rápido, mas com risco de conflito.
Agora você já percebeu que “problemas de concorrência” não é só um termo de entrevista. Inúmeras threads operárias entram e saem sem parar de um depósito compartilhado chamado heap. Pôr ordem no meio desse caos é o que mostra a competência de um desenvolvedor backend.
Mas espere: quando os operários são muitos, como se decide quem faz primeiro o trabalho de quem? Como o gerente da fábrica (o SO) administra centenas de operários? Na próxima vez, vamos falar da tarefa que mais dá dor de cabeça ao gerente da fábrica: o “escalonamento (scheduling) e a troca de contexto (context switching)”.


