JDK-8371045 : Socket I/O during class loading in a virtual thread may cause a deadlock
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 22,26
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • OS: linux
  • CPU: generic
  • Submitted: 2025-10-31
  • Updated: 2025-11-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdUnresolved
Related Reports
Blocks :  
Causes :  
Description
A DESCRIPTION OF THE PROBLEM :
Socket uses `sun.nio.ch.Poller` to handle I/O operations.
In JDK 25, a new mode was added that uses virtual threads as I/O worker. When running in a Linux environment or system property 'jdk.pollerMode' is '2', 'Mode.VTHREAD_POLLERS' will be selected, in which case virtual threads will be used. 
The following is the JDK source code:

------sun.nio.ch.Poller source code begin---------------------
  Pollers() throws IOException {
            PollerProvider provider = PollerProvider.provider();
            Poller.Mode mode;
            String s = System.getProperty("jdk.pollerMode");
            if (s != null) {
                if (s.equalsIgnoreCase(Mode.SYSTEM_THREADS.name()) || s.equals("1")) {
                    mode = Mode.SYSTEM_THREADS;
                } else if (s.equalsIgnoreCase(Mode.VTHREAD_POLLERS.name()) || s.equals("2")) {
                    mode = Mode.VTHREAD_POLLERS;
                } else {
                    throw new RuntimeException("Can't parse '" + s + "' as polling mode");
                }
            } else {
                mode = provider.defaultPollerMode();
            }
------source code end---------------------

But class loading running in virtual thread of JDK 25 still bring thread pinning
When all carrier threads are pinned by virtual threads which are waiting class loading, if a socket operation needs to be performed during class loading, the Poller handling this socket operation will be unable to acquire a carrier thread.
This will result in a request failure, and in the worst case, a deadlock will occur, class loading will never complete

This can be reproduced through code.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
run the code below:
---------- BEGIN SOURCE ----------
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.CountDownLatch;

public class Test{
    static void main() throws Exception {
        String isLinux = System.getProperty("os.name").toLowerCase();
        if (!isLinux.contains("linux")) {
            System.setProperty("jdk.pollerMode", "2");
        }

        int parallelism = Runtime.getRuntime().availableProcessors();
        CountDownLatch latch = new CountDownLatch(parallelism);

        System.out.println("checkpoint");

        for (int i = 0; i < parallelism; i++) {
            Thread.startVirtualThread(() -> {
                try {
                    new Tcp();//call Socket.connect during class loading
                } finally {
                    latch.countDown();
                }
            });
        }
        Thread.sleep(10);

        latch.await();
        System.out.println("All tasks completed");
    }

    static class Tcp {
        static {
            try (Socket socket = new Socket()) {
                socket.connect(new InetSocketAddress("bugreport.java.com", 443));
                System.out.println("Connected to bugreport.java.com");
            } catch (Exception e) {

            }
        }
    }
}


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
-------------ouput in console:------------
checkpoint
Connected to bugreport.java.com
All tasks completed
ACTUAL -
-------------ouput in console:------------
checkpoint

//the proceess will never complete
Comments
JDK-8369238 is in progress for JDK 26 so that virtual threads can be preempted in most cases where they are waiting for a class to be initialized. In the example here, they would be preempted when waiting for PollerTest$Tcp to be initialzed.
31-10-2025

As already noted, JDK-8369238 is in progress for JDK 26. For the Linux specific issue reported here, running with -Djdk.pollerMode=1 will workaround the issue. Separately, once we have another intrinsic in place for testing if pinned, then virtual threads doing I/O ops when pinned will block in the poll syscall rather than park.
31-10-2025

The observations on Windows 11: JDK 21: Passed, connected to bugreport.java.com JDK 22: Failed, the proceess hang JDK 26ea+17: Failed. Impact -> H (Regression) Likelihood -> L (Happens on specific cases) Workaround -> M (Somewhere in-between the extremes) Priority -> P3
31-10-2025