Processos e threads: trabalhando sozinho versus usando automemórias

📖 11min read

Conhecimento como autoapresentação de 1 minuto para entrevista

“Qual é a diferença entre um processo e um thread?”

Quando eu estava procurando emprego, essa pergunta sempre estava incluída nas ‘10 perguntas mais comuns em entrevistas’. Eu respondi como uma máquina.

“Um processo é um programa em execução e um thread é uma unidade de fluxo executada dentro de um processo. Os processos não compartilham recursos, mas os threads compartilham recursos.”

O entrevistador assentiu e presumi ter entendido esse conceito perfeitamente. No entanto, até encontrar o ‘Problema de Simultaneidade’ na prática, eu não tinha ideia do verdadeiro medo contido naquela frase.

“Por que o número de visualizações deveria aumentar em 100, mas só aumenta em 98?” “Por que o site para quando faço download do Excel?”

Meu código era perfeito quando eu o executava sozinho, mas ficava uma bagunça quando vários usuários entravam ao mesmo tempo. Achei que isso seria resolvido simplesmente aumentando o número de ‘trabalhadores’, mas não sabia que à medida que o número de trabalhadores aumenta, o custo de gerenciá-los (troca de contexto) aumenta exponencialmente.

Quando você trabalha sozinho, é pacífico, mas quando você trabalha com outras pessoas, a guerra começa.

Fábrica e trabalhadores no centro de logística digital

Voltemos à nossa visão de mundo do “centro de logística digital”. Executar um programa em um computador é como montar uma ‘fábrica’ em um centro de distribuição.

1. Processo: Local de trabalho independente

2. Tópico: Trabalhadores na oficina

Threads têm um ‘espaço compartilhado (Heap)’ e um ‘espaço independente (Stack)’.

[Verificação de código] Tragédia de compartilhamento (problema de simultaneidade)

“Threads compartilham recursos.” Isto pode parecer uma vantagem na sala de entrevista, mas na prática pode ser a semente do ‘desastre’.

Você se lembra do ‘Heap’ que aprendemos da última vez? Threads compartilham esta área de heap. Isso significa que o thread B pode substituir os dados nos quais o thread A está trabalhando.

Isso é chamado de ‘Condição de corrida’. Vamos verificar com código.

public class RaceConditionTest {
    static int count = 0; // Variavel compartilhada armazenada no Heap

    public static void main(String[] args) throws InterruptedException {
        // Contratar 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(); // Comecar o trabalho!
        t2.start(); // Comecar o trabalho!
        
        t1.join(); // Aguardar ate terminar o expediente
        t2.join(); // Aguardar ate terminar o expediente
        
        System.out.println("Resultado final: " + count);
    }
}

Resultado esperado: como duas pessoas somaram 10.000 vezes, o resultado deve ser 20.000.

Resultado real: 15.482, 18.931… O valor é diferente toda vez que eu o executo e 20.000 não é exibido.

Motivo:

Essa é a identidade do bug de que “às vezes os dados são mastigados” na prática. Esta é uma tragédia que ocorreu quando os trabalhadores tocaram no mesmo livro sem falar uns com os outros.

Se compararmos esta situação com um banco de dados (BD), é o mesmo que ‘uma situação em que múltiplas consultas são realizadas simultaneamente sem uma transação’. Se o saldo da conta bancária for modificado simultaneamente sem bloqueio, ocorre um terrível acidente em que o dinheiro evapora. Assim como protegemos os dados com ROLLBACK ou COMMIT no banco de dados, um dispositivo de bloqueio como Synchronized é absolutamente necessário no nível do código.

Compensação na prática: multiprocesso vs. multithread

Então, quando e o que você deve usar na prática?

1. Navegador Chrome preferido: vários processos

No antigo Internet Explorer, quando uma guia parava, todo o navegador desligava (método multithread). No entanto, o Chrome inicia cada guia como um “processo separado (fábrica)”.

2. Escolha do servidor web (Spring, Node.js, etc.): Multithreaded

O servidor deve lidar com milhares de solicitações. Se você construir um processo (fábrica) para cada solicitação, o servidor irá travar. Portanto, ele é processado por vários threads (workers) em um processo.

Você prefere construir uma ‘fortaleza’ segura, mas cara, ou pilotar um ‘drone’ rápido, mas perigoso?

Encerramento: a autoimolação traz responsabilidade

Hoje analisamos “processos e threads”, a forma como os trabalhadores trabalham.

Agora você sabe que o termo ‘problemas de simultaneidade’ não é apenas um termo de entrevista. Vários trabalhadores de thread estão constantemente entrando e saindo de um warehouse compartilhado chamado Heap. É habilidade de um desenvolvedor back-end criar ordem nesse caos.

Mas espere, se há muitos trabalhadores, como você decide quem deve fazer o trabalho de quem primeiro? Como um gerente de fábrica (OS) gerencia centenas de trabalhadores? Na próxima vez, falaremos sobre a tarefa mais problemática do gerente de fábrica, ‘Agendamento e troca de contexto’.

Deixe um comentário