Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java 25 virtual threads and monitors: version boundaries still matter

Last updated: 29 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A virtual thread executes on carrier threads, and the monitor-related carrier-pinning behavior changed in JDK 24 without removing the monitor’s mutual-exclusion contract.

Download Java source kit

Java 25+. The program uses JDK classes and requires no preview flags.

Separate contention from carrier retention

A synchronized operation still allows only one holder of a particular monitor at a time. Removing the older monitor-related pinning behavior does not make all requests inside that critical section execute concurrently. A slow operation under one shared monitor can remain an application bottleneck.

The Java 21 lesson is labelled for that release. Its synchronized-block pinning warning should not be generalized to every newer JDK. This Java 25 fixture checks completed increments under a monitor and uses virtual threads, but it does not infer carrier behavior from elapsed time.

Native or foreign calls can introduce other blocking or pinning boundaries. Runtime diagnostics and the actual call path matter. A virtual thread also does not create more database connections, CPU cores or queue capacity; downstream admission remains a separate application rule.

Wait for completion before reading shared state

The program joins every worker before printing the count. The protected increment prevents lost updates, while joining supplies a completion boundary for the final read. A collection of started Thread objects alone does not prove that their operations finished successfully in a larger application.

Working program

Java
import java.util.*;
public class MonitoredVirtualReceipts {
    final Object monitor=new Object();int accepted;
    void accept(){synchronized(monitor){accepted++;}}
    public static void main(String[] args)throws Exception{
        MonitoredVirtualReceipts service=new MonitoredVirtualReceipts();List<Thread> workers=new ArrayList<>();
        for(int i=0;i<40;i++)workers.add(Thread.ofVirtual().start(service::accept));
        for(Thread worker:workers)worker.join();
        System.out.println(service.accepted);
    }
}

Output

Output
40

Costs and boundaries

There are n operations and n retained worker handles. The monitor serializes their increments, so virtual threads do not establish parallel speedup for that section. This program verifies the state result on Java 25; timing, native-call behavior and carrier scheduling need separate diagnostic evidence.

Common Mistakes

  • Less monitor pinning does not remove lock contention.
  • A release-specific warning is not a timeless rule.
  • Uncaught worker failure requires explicit reporting in application code.

Read next

Java 21 baseline, Mutual exclusion, Runtime evidence.

java
virtual-thread-monitors
Storage details