env
- mysql-connector-java:8.0.33
- java version:jdk21
- springboot:3.2.1
- virtual thread mode: true
- connector pool: hikari
problem
- It seems that mysql-connector-java has many synchronized which pinned the carrier thread.
- How to solve this problem?
The trace stack info
Thread[#93,ForkJoinPool-1-worker-4,5,CarrierThreads]
java.base/java.lang.VirtualThread$VThreadContinuation.onPinned(VirtualThread.java:185)
java.base/jdk.internal.vm.Continuation.onPinned0(Continuation.java:393)
java.base/java.lang.VirtualThread.parkNanos(VirtualThread.java:631)
java.base/java.lang.System$2.parkVirtualThread(System.java:2648)
java.base/jdk.internal.misc.VirtualThreads.park(VirtualThreads.java:67)
java.base/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:408)
java.base/sun.nio.ch.Poller.pollIndirect(Poller.java:137)
java.base/sun.nio.ch.Poller.poll(Poller.java:102)
java.base/sun.nio.ch.Poller.poll(Poller.java:87)
java.base/sun.nio.ch.NioSocketImpl.park(NioSocketImpl.java:175)
java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:280)
java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:304)
java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:346)
java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:796)
java.base/java.net.Socket$SocketInputStream.read(Socket.java:1099)
com.mysql.cj.protocol.ReadAheadInputStream.fill(ReadAheadInputStream.java:107)
com.mysql.cj.protocol.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:150)
com.mysql.cj.protocol.ReadAheadInputStream.read(ReadAheadInputStream.java:180) <== monitors:1
java.base/java.io.FilterInputStream.read(FilterInputStream.java:119)
com.mysql.cj.protocol.FullReadInputStream.readFully(FullReadInputStream.java:64)
com.mysql.cj.protocol.a.SimplePacketReader.readHeaderLocal(SimplePacketReader.java:81)
com.mysql.cj.protocol.a.SimplePacketReader.readHeader(SimplePacketReader.java:63)
com.mysql.cj.protocol.a.SimplePacketReader.readHeader(SimplePacketReader.java:45)
com.mysql.cj.protocol.a.TimeTrackingPacketReader.readHeader(TimeTrackingPacketReader.java:52)
com.mysql.cj.protocol.a.TimeTrackingPacketReader.readHeader(TimeTrackingPacketReader.java:41)
com.mysql.cj.protocol.a.MultiPacketReader.readHeader(MultiPacketReader.java:54)
com.mysql.cj.protocol.a.MultiPacketReader.readHeader(MultiPacketReader.java:44)
com.mysql.cj.protocol.a.NativeProtocol.readMessage(NativeProtocol.java:576)
com.mysql.cj.protocol.a.NativeProtocol.checkErrorMessage(NativeProtocol.java:762)
com.mysql.cj.protocol.a.NativeProtocol.sendCommand(NativeProtocol.java:701)
com.mysql.cj.protocol.a.NativeProtocol.sendCommand(NativeProtocol.java:156)
com.mysql.cj.NativeSession.ping(NativeSession.java:733)
com.mysql.cj.jdbc.ConnectionImpl.pingInternal(ConnectionImpl.java:1478)
com.mysql.cj.jdbc.ConnectionImpl.isValid(ConnectionImpl.java:2516) <== monitors:1
com.zaxxer.hikari.pool.PoolBase.isConnectionDead(PoolBase.java:157
A very simple answer: don't call mySQL JDBC Connector on virtual thread to avoid pinning. Unless you are going to rewrite mySQL JDBC Connector, of course. Java is full of
synchronizedand even such a popular and excellent multithreading tool likejava.util.concurrent.ConcurrentHashMaphas it and it would be impossible to replace allsynchronizedand other pinning actions with non-pinning alternatives overnight. Project Loom and virtual threads are not yet stable enough and mature enough to warrant such immense refactoring. So, the best thing you can do is to avoid using virtual threads for frequently pinning code (while occasional pinning might be tolerable)By other hand, if a virtual thread is pinned, it may not (or should not, if it is not a JDK bug) cause your system to hang indefinitely or die or anything like that. While this virtual thread remains pinned, the correspondent Carrier (platform) thread will be just excluded from Carriers thread pool. When the pinning action, e.g.
Thread.sleep, completes, the pinned thread should become unpinned. Pinning, of course, decreases the performance of virtual threads machinery and itself is a misuse of it, but it should not be a reason for your system death. (Unless you stressed things to improbable extent, which may or may not be your personal case).