Re: Naïve Tomcat experiment--does this indicate pinning?

Cay Horstmann cay at horstmann.com
Thu May 5 05:19:35 UTC 2022


Il 04/05/2022 21:09, Cay Horstmann ha scritto:
> I use
> 
>  
> public class VirtualThreadExecutor
>     extends org.apache.catalina.core.StandardThreadExecutor {
> 
>     private ExecutorService exec = Executors.newThreadPerTaskExecutor(
 >        Thread.ofVirtual().name("myfactory-", 1).factory());>     
public static ExtentLocal<Instant> submissionTime =
> ExtentLocal.newInstance();
>     public static ExtentLocal<Instant> creationTime = 
> ExtentLocal.newInstance();
> 
>     public void execute(Runnable command) {
>        var smt = Instant.now();
>        exec.submit(() ->
>           ExtentLocal
>              .where(submissionTime, smt)
>              .where(creationTime, Instant.now())
>              .run(command));
>     }
>     ...
> }
> 
> In a servlet, I print out both times, as well as the thread IDs. When 
> invoking it 200 times, the first time I get
> 
> Submitted: 2022-05-04T18:28:49.467115874Z
> Created: 2022-05-04T18:28:49.469110411Z
> 
> After 200 requests:
> 
> Submitted: 2022-05-04T18:28:49.710324863Z
> Created: 2022-05-04T18:29:01.802042721Z
> 

The servlet sleeps for (int) (1000 * Math.random()) millis. I take a 
thread dump right after firing 200 requests. 9 threads park on sleep 
with a stack trace shown below. The rest show up as

          {
            "tid": 616,
            "name": "myfactory-562",
            "stack": [
            ]
          },

which I guess means "Not started yet". I could not see anything that 
Tomcat does wrong. Tomcat has launched the virtual threads for all 
requests, and none of them shows up as doing anything nefarious. I 
expected to see 200 sleeping virtual threads, or a bunch of messages 
about pinned threads. (I ran with -Djdk.tracePinnedThreads=full)

There were none in these runs. But wait, way back when, I did see a 
couple. And this time I happen to notice that line had a curious arrow 
like this:

org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) 
<== monitors:1

Looking at SocketProcessorBase.run, I found a synchronized block. 
Replacing it with a ReentrantLock solved the problem.

So there is a happy ending, but couldn't it have been happier? Would it 
be possible to report such a problem more clearly?

Cheers,

Cay


Typical stack trace of an active thread:

          {
            "tid": 492,
            "name": "myfactory-438",
            "stack": [
               "java.base\/jdk.internal.misc.Unsafe.park(Native Method)",
 
"java.base\/java.lang.VirtualThread.parkOnCarrierThread(VirtualThread.java:588)",
 
"java.base\/java.lang.VirtualThread.doParkNanos(VirtualThread.java:564)",
 
"java.base\/java.lang.VirtualThread.parkNanos(VirtualThread.java:523)",
 
"java.base\/java.lang.VirtualThread.doSleepNanos(VirtualThread.java:735)",
 
"java.base\/java.lang.VirtualThread.sleepNanos(VirtualThread.java:708)",
               "java.base\/java.lang.Thread.sleep(Thread.java:448)",
               "com.horstmann.MyServlet.doGet(MyServlet.java:23)",
 
"jakarta.servlet.http.HttpServlet.service(HttpServlet.java:668)",
 
"jakarta.servlet.http.HttpServlet.service(HttpServlet.java:777)",
 
"org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223)",
 
"org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)",
 
"org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)",
 
"org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)",
 
"org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)",
 
"org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)",
 
"org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)",
 
"org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)",
 
"org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119)",
 
"org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)",
 
"org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)",
 
"org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)",
 
"org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:356)",
 
"org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)",
 
"org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)",
 
"org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:867)",
 
"org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1715)",
 
"org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)",
 
"java.base\/jdk.internal.vm.ExtentLocalContainer.runWithoutScope(ExtentLocalContainer.java:114)",
 
"java.base\/jdk.internal.vm.ExtentLocalContainer.run(ExtentLocalContainer.java:100)",
 
"jdk.incubator.concurrent\/jdk.incubator.concurrent.ExtentLocal$Carrier.run(ExtentLocal.java:327)",
 
"com.horstmann.VirtualThreadExecutor.lambda$execute$0(VirtualThreadExecutor.java:25)",
 
"java.base\/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:577)",
 
"java.base\/java.util.concurrent.ThreadPerTaskExecutor$ThreadBoundFuture.run(ThreadPerTaskExecutor.java:344)",
 
"java.base\/java.lang.VirtualThread.run(VirtualThread.java:287)",
 
"java.base\/java.lang.VirtualThread$VThreadContinuation.lambda$new$0(VirtualThread.java:174)",
 
"java.base\/jdk.internal.vm.Continuation.enter0(Continuation.java:326)",
 
"java.base\/jdk.internal.vm.Continuation.enter(Continuation.java:319)"
            ]
          },

A pinning report:

Thread[#39,ForkJoinPool-1-worker-1,5,CarrierThreads]
 
java.base/java.lang.VirtualThread$VThreadContinuation.onPinned(VirtualThread.java:180)
     java.base/jdk.internal.vm.Continuation.onPinned0(Continuation.java:397)
     java.base/jdk.internal.vm.Continuation.yield0(Continuation.java:389)
     java.base/jdk.internal.vm.Continuation.yield(Continuation.java:356)
 
java.base/java.lang.VirtualThread.yieldContinuation(VirtualThread.java:370)
     java.base/java.lang.VirtualThread.doParkNanos(VirtualThread.java:552)
     java.base/java.lang.VirtualThread.parkNanos(VirtualThread.java:523)
     java.base/java.lang.VirtualThread.doSleepNanos(VirtualThread.java:735)
     java.base/java.lang.VirtualThread.sleepNanos(VirtualThread.java:708)
     java.base/java.lang.Thread.sleep(Thread.java:448)
     com.horstmann.MyServlet.doGet(MyServlet.java:23)
     jakarta.servlet.http.HttpServlet.service(HttpServlet.java:668)
     jakarta.servlet.http.HttpServlet.service(HttpServlet.java:777)
 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223)
 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
     org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
 
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185)
 
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158)
 
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
 
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
 
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
 
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119)
 
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
 
org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
 
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
 
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:356)
 
org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
 
org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
 
org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:867)
 
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1716)
 
org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) 
<== monitors:1
 
java.base/jdk.internal.vm.ExtentLocalContainer.runWithoutScope(ExtentLocalContainer.java:114)
 
java.base/jdk.internal.vm.ExtentLocalContainer.run(ExtentLocalContainer.java:100)
 
jdk.incubator.concurrent/jdk.incubator.concurrent.ExtentLocal$Carrier.run(ExtentLocal.java:327)
 
com.horstmann.VirtualThreadExecutor.lambda$execute$0(VirtualThreadExecutor.java:20)
 
java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:577)
 
java.base/java.util.concurrent.ThreadPerTaskExecutor$ThreadBoundFuture.run(ThreadPerTaskExecutor.java:344)
     java.base/java.lang.VirtualThread.run(VirtualThread.java:287)
 
java.base/java.lang.VirtualThread$VThreadContinuation.lambda$new$0(VirtualThread.java:174)
     java.base/jdk.internal.vm.Continuation.enter0(Continuation.java:326)
     java.base/jdk.internal.vm.Continuation.enter(Continuation.java:319)

-- 

Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com


More information about the loom-dev mailing list