<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/what-jstack-misses-when-your-java-service-uses-virtual-threads-tgd0brhjs" -->

---
title: What jstack Misses When Your Java Service Uses Virtual...
description: Standard jstack and jcmd Thread.print dumps don't show virtual threads on JDK 21 through 25, only the platform carrier threads that run them. Use jcmd <pid>...
canonical: https://daily.dev/posts/what-jstack-misses-when-your-java-service-uses-virtual-threads-tgd0brhjs
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: What jstack Misses When Your Java Service Uses Virtual Threads | daily.dev
og:description: Standard jstack and jcmd Thread.print dumps don't show virtual threads on JDK 21 through 25, only the platform carrier threads that run them. Use jcmd <pid>...
og:url: https://daily.dev/posts/what-jstack-misses-when-your-java-service-uses-virtual-threads-tgd0brhjs
og:image: https://api.daily.dev/og/posts/TGd0BrHjs.png
og:image:alt: What jstack Misses When Your Java Service Uses Virtual Threads
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# What jstack Misses When Your Java Service Uses Virtual Threads

**[Foojay.io](https://daily.dev/sources/foojayio)** · 8 min read · 0 upvotes · 0 comments

## Summary

Standard jstack and jcmd Thread.print dumps don't show virtual threads on JDK 21 through 25, only the platform carrier threads that run them. Use jcmd <pid> Thread.dump_to_file instead, which has existed since JDK 21 and can output plain text or, with -format=json, JSON. JDK 25's format adds thread state, timestamps and lock info; JSON lets you group threads by executor or structured-concurrency container. The author also covers carrier pinning: parkOnCarrierThread marks a parked thread still holding its carrier, a pattern fixed for synchronized blocks by JEP 491 in JDK 24, with jdk.VirtualThreadPinned JFR events (20ms threshold) available since JDK 21.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://foojay.io/today/what-jstack-misses-when-your-java-service-uses-virtual-threads>

## Questions this post answers

### Why doesn't jstack show my virtual threads in a Spring Boot service on JDK 21?

jstack and jcmd Thread.print only show platform threads, including the carrier threads virtual threads run on, not the virtual threads themselves, on JDK 21 through 25. When a virtual thread unmounts to wait on I/O, its carrier becomes idle and free to run something else, so a thread dump can show low CPU and idle workers even with thousands of requests queued.

_daily.dev surfaces practical fixes like this for anyone debugging virtual-thread backlogs in production Java services._

### How do I capture a thread dump that includes virtual threads in Java?

Run jcmd <pid> Thread.dump_to_file /tmp/dump.txt for plain text, available since JDK 21, or add -format=json for JSON output. The JVM writes the file to the target process's own filesystem, which matters in containers, and won't overwrite an existing file unless you pass -overwrite. JDK 25 output adds thread state, timestamps, and lock information compared to JDK 21 through 24.

_Developers tracking JDK debugging changes like this one often follow release notes on daily.dev before an incident hits._

### Does JDK 24 fix virtual thread pinning caused by synchronized blocks?

Yes, JEP 491 in JDK 24 removes the pinning caused by a virtual thread holding a monitor via synchronized while blocking, a path that still applied on JDK 21 through 23. Native frames and class initialization can still cause pinning on JDK 24. The jdk.VirtualThreadPinned JFR event, enabled by default with a 20ms threshold since JDK 21, helps catch pinning that comes and goes; jdk.tracePinnedThreads was removed in JDK 24.

_Teams upgrading JVM versions can track breaking changes like JEP 491's pinning fix on daily.dev._

## Similar posts on daily.dev

- [Your Loom App Quietly Became a Thread Pool Again: A Field Guide to Virtual Thread Pinning](https://daily.dev/posts/your-loom-app-quietly-became-a-thread-pool-again-a-field-guide-to-virtual-thread-pinning-sbxl9qgff) · Foojay.io · 1 upvotes · 0 comments
- [Virtual Threads After JDK 24: What Changed for Production Java](https://daily.dev/posts/virtual-threads-after-jdk-24-what-changed-for-production-java-1iad53gy7) · InfoQ · 0 upvotes · 0 comments
- [Synchronize Virtual Thread Without Pinning](https://daily.dev/posts/synchronize-virtual-thread-without-pinning-xujbj1bjy) · Baeldung · 7 upvotes · 0 comments
- [JDK 27: Numeric Fields in JSON Thread Dumps – Inside.java](https://daily.dev/posts/jdk-27-numeric-fields-in-json-thread-dumps-inside-java-uvxsdh0re) · Inside Java · 1 upvotes · 0 comments
- [Thread Dumps and Project Loom \(Virtual Threads\)](https://daily.dev/posts/thread-dumps-and-project-loom-virtual-threads--toxvuqohy) · JetBrains · 0 upvotes · 0 comments

---

Tags: [#java](https://daily.dev/tags/java), [#jvm](https://daily.dev/tags/jvm)

[View this post on daily.dev](https://daily.dev/posts/what-jstack-misses-when-your-java-service-uses-virtual-threads-tgd0brhjs)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"What jstack Misses When Your Java Service Uses Virtual Threads","url":"https://daily.dev/posts/what-jstack-misses-when-your-java-service-uses-virtual-threads-tgd0brhjs","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/what-jstack-misses-when-your-java-service-uses-virtual-threads-tgd0brhjs"},"datePublished":"2026-10-27T01:06:43.674Z","dateModified":"2026-10-27T01:11:53.114Z","description":"Standard jstack and jcmd Thread.print dumps don't show virtual threads on JDK 21 through 25, only the platform carrier threads that run them. Use jcmd \u003cpid\u003e...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/3e60db1c64ed673f534524c18797009f?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/3e60db1c64ed673f534524c18797009f?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Foojay.io","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Foojay.io","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/1820f6a6ae944760aa322b67ed85f848","url":"https://daily.dev/sources/foojayio"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/what-jstack-misses-when-your-java-service-uses-virtual-threads-tgd0brhjs","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"java,jvm","timeRequired":"PT8M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Foojay.io","item":"https://daily.dev/sources/foojayio"},{"@type":"ListItem","position":3,"name":"What jstack Misses When Your Java Service Uses Virtual Threads"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/what-jstack-misses-when-your-java-service-uses-virtual-threads-tgd0brhjs#faq","mainEntity":[{"@type":"Question","name":"Why doesn't jstack show my virtual threads in a Spring Boot service on JDK 21?","acceptedAnswer":{"@type":"Answer","text":"jstack and jcmd Thread.print only show platform threads, including the carrier threads virtual threads run on, not the virtual threads themselves, on JDK 21 through 25. When a virtual thread unmounts to wait on I/O, its carrier becomes idle and free to run something else, so a thread dump can show low CPU and idle workers even with thousands of requests queued. daily.dev surfaces practical fixes like this for anyone debugging virtual-thread backlogs in production Java services."}},{"@type":"Question","name":"How do I capture a thread dump that includes virtual threads in Java?","acceptedAnswer":{"@type":"Answer","text":"Run jcmd \u003cpid\u003e Thread.dump_to_file /tmp/dump.txt for plain text, available since JDK 21, or add -format=json for JSON output. The JVM writes the file to the target process's own filesystem, which matters in containers, and won't overwrite an existing file unless you pass -overwrite. JDK 25 output adds thread state, timestamps, and lock information compared to JDK 21 through 24. Developers tracking JDK debugging changes like this one often follow release notes on daily.dev before an incident hits."}},{"@type":"Question","name":"Does JDK 24 fix virtual thread pinning caused by synchronized blocks?","acceptedAnswer":{"@type":"Answer","text":"Yes, JEP 491 in JDK 24 removes the pinning caused by a virtual thread holding a monitor via synchronized while blocking, a path that still applied on JDK 21 through 23. Native frames and class initialization can still cause pinning on JDK 24. The jdk.VirtualThreadPinned JFR event, enabled by default with a 20ms threshold since JDK 21, helps catch pinning that comes and goes; jdk.tracePinnedThreads was removed in JDK 24. Teams upgrading JVM versions can track breaking changes like JEP 491's pinning fix on daily.dev."}}]}
```

