Virtual Threads no Java: A Revolução que Simplificou a Alta Performance

Se trabalha com Java, provavelmente já ouviu falar do Virtual Threads. Lançadas oficialmente no Java 21, elas não são apenas uma “atualizaçãozinha” no código; elas representam uma mudança de paradigma na forma como pensamos em escalabilidade e concorrência.

Neste artigo, vamos traduzir a complexidade técnica para entender por que elas são o “santo graal” para quem precisa de sistemas rápidos, eficientes e, acima de tudo, fáceis de manter.

1. O Problema: O “Peso” das Threads Antigas

Até há pouco tempo, cada thread no Java era uma Thread de Plataforma. Imagine que cada thread é um funcionário especializado que exige um escritório próprio e caro (cerca de 1MB de memória de reserva). Se recebesse 2.000 pedidos ao mesmo tempo, precisaria de 2.000 escritórios. Rapidamente, o prédio (o seu servidor) ficaria sem espaço, mesmo que os funcionários estivessem apenas à espera que um e-mail (ou uma resposta da base de dados) chegasse.

Isto forçava os desenvolvedores a usar a “programação reativa” (como WebFlux ou RxJava) — uma técnica poderosa, mas extremamente complexa de ler, escrever e debugar. Era como se, para poupar espaço no prédio, tivéssemos de aprender uma língua nova e difícil.

2. A Solução: O que são as Virtual Threads?

As Virtual Threads são threads “peso-pena”. Em vez de 1MB, elas ocupam apenas alguns kilobytes de memória inicial. Elas não são geridas diretamente pelo sistema operativo, mas sim pela própria Máquina Virtual Java (JVM).

A grande diferença:

  • Threads de Plataforma: Consegue criar milhares (o limite é o SO).
  • Virtual Threads: Consegue criar milhões no mesmo hardware comum.

Elas permitem que volte ao modelo simples de “uma thread por requisição”, sem o medo de deitar o servidor abaixo.

3. Os Bastidores: Carrier Threads e o “Agendamento”

Para entender a “magia”, precisamos de conhecer as Carrier Threads (Threads Transportadoras).

Imagine que as Virtual Threads são passageiros e as Threads de Plataforma são os assentos de um avião.

  1. Uma Virtual Thread precisa de executar código.
  2. A JVM “monta” essa Virtual Thread num assento (uma Carrier Thread).
  3. Assim que a Virtual Thread precisa de esperar por algo (I/O), ela levanta-se do assento.
  4. O assento fica livre imediatamente para outro passageiro (outra Virtual Thread) trabalhar.

Este processo de “montar” e “desmontar” é extremamente rápido e invisível para si.

4. Como a Mágica Acontece na Prática?

O segredo está no bloqueio. No modelo antigo, se um cliente estivesse a decidir o prato (operação de I/O), o garçom (a CPU) ficava parado à frente dele, bloqueado e inútil para os outros.

Com as Virtual Threads, no momento em que o código faz uma chamada de rede ou consulta ao banco de dados, o Java deteta que haverá uma espera. Ele suspende a Virtual Thread, liberta a CPU para outras tarefas e, quando a resposta chega, a thread é retomada exatamente onde parou. O “garçom” nunca fica parado.

Exemplo de código: Como criar uma?

É tão simples quanto isto:

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    executor.submit(() -> {
        System.out.println("Olá de uma Virtual Thread!");
        // Simula uma espera de rede
        Thread.sleep(Duration.ofSeconds(1));
        return "Sucesso";
    });
}

5. Onde usar (e onde NÃO usar)

Não tente usar Virtual Threads para tudo. Existe um cenário onde elas brilham e outro onde são irrelevantes:

  • ✅ Use em tarefas de I/O (I/O-Bound): Chamadas de API, consultas a bases de dados, leitura de ficheiros e microserviços. É aqui que o ganho de escalabilidade é massivo.
  • ❌ Evite em tarefas de CPU (CPU-Bound): Cálculos matemáticos complexos, processamento de vídeo ou criptografia pesada. Nesses casos, a CPU é o gargalo real; criar mais threads não vai acelerar o cálculo, só vai criar confusão na gestão.

6. Atenção às “Ciladas” no Caminho

Mesmo sendo fantásticas, as Virtual Threads têm algumas particularidades que podem comprometer a performance se ignoradas:

O Problema do “Pinning” (Fixação)

Até versões anteriores ao Java 24, se usasse a palavra-chave synchronized ou chamasse código nativo (JNI) dentro de uma Virtual Thread, ela ficava “colada” à Carrier Thread e não conseguia ser desmontada durante a espera.

  • Dica: Atualize para o Java 24 (onde isto foi muito melhorado) ou substitua synchronized por ReentrantLock.

Esqueça os Pools de Threads

Estamos habituados a criar pools (como o FixedThreadPool) para não esgotar recursos. Com Virtual Threads, a regra muda: não faça pooling. Elas foram feitas para serem descartáveis. Se precisar de limitar o acesso a um recurso (como uma base de dados que só aguenta 10 conexões), use um Semaphore, não limite o número de threads.

Cuidado com o ThreadLocal e os Scoped Values

Ter milhões de threads significa que, se cada uma guardar um objeto pesado no ThreadLocal, a sua memória RAM vai desaparecer num instante. O Java introduziu os Scoped Values (finalizados no Java 25) como uma alternativa muito mais leve e segura para partilhar dados entre tarefas.

7. O Ecossistema já está pronto!

A melhor notícia é que não precisa de implementar tudo do zero. As principais ferramentas já suportam Virtual Threads:

  • Spring Boot 3.2+: Basta uma propriedade no application.properties (spring.threads.virtual.enabled=true) para que o Tomcat passe a usar Virtual Threads.
  • Quarkus, Micronaut e Hibernate: Todos já possuem integrações nativas para tirar proveito desta velocidade.

8. Conclusão: O Futuro é Simples

As Virtual Threads trazem o melhor de dois mundos: a escalabilidade massiva que antes só se conseguia com código reativo complexo, mas com a simplicidade do código sequencial que qualquer programador Java sabe escrever e debugar.

Se quer preparar a sua aplicação para o próximo nível:

  1. Migre para o Java 21 (LTS) ou superior.
  2. Identifique os seus maiores tempos de espera (I/O).
  3. Ative as Virtual Threads nas suas frameworks e deixe a JVM fazer o trabalho pesado de gestão de recursos.

O Java nunca foi tão ágil, moderno e eficiente!

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *