-
Bug
-
Resolution: Unresolved
-
P3
-
None
-
22, 26
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
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
- caused by
-
JDK-8318422 Allow poller threads be virtual threads
-
- Resolved
-