Java3 min de leitura

Virtual Threads - Pinning e Saturação

Java 21: Não deixe o "Pinning" sabotar a performance das suas Virtual Threads

Virtual Threads - Pinning

Com o lançamento do Java 21, a comunidade de desenvolvedores recebeu as Virtual Threads, uma funcionalidade revolucionária que promete um throughput massivo e alta escalabilidade para aplicações modernas. Contudo, existe um comportamento técnico conhecido como Pinning que pode anular esses ganhos se não for tratado corretamente.


Faça os teste locais: Virtual-Threads - Pinning - E se você gostou, me deixe uma estrelinha ⭐


O que são Virtual Threads?

Diferente das threads de plataforma tradicionais, as Virtual Threads são entidades leves gerenciadas pela JVM e armazenadas na Heap. O grande diferencial de performance está no processo de Mounting (montagem) e Unmounting (desmontagem): quando uma thread virtual encontra uma operação de bloqueio, a JVM a remove da thread real da CPU (carrier thread), liberando esse recurso para processar outras tarefas simultâneas.


O Problema: O que é o Pinning?

O Pinning (estacionamento) ocorre quando uma thread virtual fica "presa" à sua carrier thread e não pode ser desmontada durante um bloqueio. Quando isso acontece, tanto a thread virtual quanto a thread do sistema operacional subjacente ficam bloqueadas, impedindo a escalabilidade massiva prometida pela tecnologia.

Os dois principais cenários que causam pinning atualmente são:

  1. Execução de código dentro de um bloco ou método synchronized.
  2. Invocação de funções estrangeiras ou métodos nativos (via JNI ou a nova Foreign Function & Memory API).

Por que o synchronized é perigoso?

Se um bloco synchronized contiver uma operação de bloqueio (como I/O ou Thread.sleep()), a thread virtual ficará pinned à thread portadora. Em testes práticos, uma carga de 25 tarefas executadas em 8 núcleos de CPU pode ocupar todos os 8 trabalhadores do sistema simultaneamente, criando um gargalo desnecessário e anulando a vantagem das threads leves.


A Solução: ReentrantLock

A solução recomendada para o Java moderno é refatorar os blocos sincronizados, substituindo-os por travas da API java.util.concurrent, especificamente o ReentrantLock. Diferente do synchronized, o ReentrantLock permite que a JVM realize o unmounting da thread virtual com sucesso durante o bloqueio, permitindo que a CPU seja reutilizada para outras milhares de threads virtuais que aguardam processamento.


Exemplo Prático de Refatoração

Código com Pinning (Vulnerável):

<span class="hljs-comment">// Causa PINNING e esgota os workers da CPU</span>
<span class="hljs-keyword">synchronized</span> (lockObject) {
    <span class="hljs-keyword">try</span> {
        Thread.sleep(<span class="hljs-number">1000</span>); <span class="hljs-comment">// Operação de bloqueio</span>
    } <span class="hljs-keyword">catch</span> (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}

Código Escalável com ReentrantLock:

<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-type">Lock</span> <span class="hljs-variable">lock</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ReentrantLock</span>();

<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">executeTask</span><span class="hljs-params">()</span> {
    lock.lock(); <span class="hljs-comment">// Permite unmounting se houver bloqueio interno</span>
    <span class="hljs-keyword">try</span> {
        Thread.sleep(<span class="hljs-number">1000</span>); 
        logger.info(<span class="hljs-string">&quot;Executado com sucesso!&quot;</span>);
    } <span class="hljs-keyword">finally</span> {
        lock.unlock(); <span class="hljs-comment">// Garantia de liberação da trava</span>
    }
}

Como monitorar o Pinning?

Para identificar se sua aplicação está sofrendo com este problema, você pode utilizar a flag de diagnóstico do JDK durante a execução:

-Djdk.tracePinnedThreads=short ou -Djdk.tracePinnedThreads=full.

Conclusão

As Virtual Threads mudaram o paradigma da concorrência no Java, mas exigem que abandonemos práticas antigas como o uso excessivo de synchronized em prol de soluções mais modernas como o ReentrantLock ssa mudança é essencial para atingir o máximo potencial de escalabilidade da plataforma.

Este artigo foi inspirado nos problemas resolvidos do livro Java Coding Problems, Second Edition (Packt Publishing).


Publicado por: Guilherme Gomes - 17/05/2026 20:11

← Voltar aos Artigos