Exploring Virtual Thread Behavior with Concurrent HTTP Calls

Understanding how virtual threads, introduced in Java 16, interact with underlying OS threads is crucial for optimizing I/O bound tasks. This code snippet demonstrates creating two virtual threads that perform calculations and make slow HTTP calls. Here, we aim to analyze the internal behavior of the JVM and OS threads during execution

Thread thread = Thread.ofVirtual().start(() -> {
 int a = 2+3; slowHttpCall();int c = a+5;Sysout(c);
});  
 
Thread.ofVirtual().start(() -> {
 int x = 2+3; slowHttpCall();int y = x+5;Sysout(y);
});

Code Analysis:

The code creates two virtual threads using Thread.ofVirtual().start(). Each thread performs the following actions:

  1. Calculates 2 + 3 and stores the result in a variable.
  2. Makes a slow httpCall() (assumed to be an I/O operation).
  3. Calculates another expression (a + 5 or x + 5) and stores the result.
  4. Prints the final result using System.out.println(c) or System.out.println(y).

Virtual Threads and OS Threads:

  • JVM Creates Virtual Threads: The JVM creates two virtual threads, thread1 and thread2, to represent the code you provided.
  • Mapping to OS Thread: The JVM might initially map both virtual threads to the same underlying OS thread provided by the operating system.

Execution Flow (Possible Scenario):

  1. 2 + 3 Calculation: The OS thread, associated with both virtual threads, executes 2 + 3 for thread1 and stores the result in a.
  2. httpCall() Initiation: When thread1 encounters slowHttpCall(), the JVM initiates the call but doesn’t necessarily block the OS thread.
  3. Potential Thread Switch: Depending on the JVM’s scheduling and the availability of other runnable virtual threads, the JVM might switch the OS thread to thread2.
  4. 2 + 3 Calculation (thread2): The OS thread now executes 2 + 3 for thread2 and stores the result in x.
  5. httpCall() Initiation (thread2): When thread2 encounters slowHttpCall(), the JVM initiates the call for thread2 as well.

Here’s where the exact behavior can vary depending on the specific JVM implementation and OS interaction:

  • OS Thread Management: The JVM might keep the OS thread associated with either thread1 or thread2 (or potentially switch it back to thread1) while the httpCall() operations are ongoing. This decision depends on factors like expected call duration and the availability of other virtual threads.
  • I/O Handling: The operating system and the JVM work together to handle the httpCall() operations asynchronously. The OS thread might not be completely blocked, and the JVM might be notified when the calls finish.

After the httpCall()s complete (assumed to be slow):

  • The JVM resumes the appropriate virtual thread (thread1 or thread2) based on the completion order of the calls.
  • The resumed virtual thread completes its remaining calculations (a + 5 or x + 5) and prints the result using System.out.println().

Important Notes:

  • The exact number of OS threads used and the switching behavior can vary depending on the JVM implementation and the operating system.
  • The code snippet doesn’t handle potential errors or timeouts during the httpCall() operations.

In essence, virtual threads provide an abstraction layer. You write code using virtual threads, and the JVM manages their execution efficiently on underlying OS threads. This allows the program to potentially avoid blocking the CPU core while waiting for I/O operations to complete.

when jvm initiates slowhttpcall of thread1 and switches OS thread to virtual thread 2…wont it need a thread for slowhttpcall also?

You’re absolutely right! When the JVM initiates the slowHttpCall() of thread1 and potentially switches the OS thread to thread2, it doesn’t necessarily need a separate thread just for the slowHttpCall(). Here’s why:

Asynchronous I/O and Non-Blocking Calls:

  • The slowHttpCall() is assumed to be an I/O operation. Modern JVMs typically leverage asynchronous I/O or non-blocking I/O techniques to handle such operations efficiently.
  • In these approaches, the thread initiating the I/O call (in this case, thread1) doesn’t block and wait for the call to complete.
  • Instead, the JVM registers the call with the operating system and continues execution with other tasks (potentially switching the OS thread to thread2).

OS and JVM Cooperation:

  • The operating system manages the underlying network communication for the slowHttpCall().
  • Once the slowHttpCall() finishes, the operating system notifies the JVM through an event or callback mechanism.

JVM Resumes the Right Thread:

  • When the JVM receives the notification for thread1‘s slowHttpCall() completion, it can resume thread1 on the available OS thread (which might be the same thread used by thread2 earlier).

Benefits:

  • This approach avoids blocking the CPU core while waiting for the slowHttpCall() to complete.
  • The JVM can utilize the OS thread for other virtual threads like thread2 while waiting for the I/O operation.

You may also like...