upvote
Regarding "What's wrong with what .NET did with threads?", see https://cr.openjdk.org/~rpressler/loom/Loom-Proposal.html (relevant part below):

  An alternative solution to that of fibers to concurrency's simplicity vs. performance issue is known as async/await, and has been adopted by C# and Node.js, and will likely be adopted by standard JavaScript. Continuations and fibers dominate async/await in the sense that async/await is easily implemented with continuations (in fact, it can be implemented with a weak form of delimited continuations known as stackless continuations, that don't capture an entire call-stack but only the local context of a single subroutine), but not vice-versa.

  While implementing async/await is easier than full-blown continuations and fibers, that solution falls far too short of addressing the problem. While async/await makes code simpler and gives it the appearance of normal, sequential code, like asynchronous code it still requires significant changes to existing code, explicit support in libraries, and does not interoperate well with synchronous code. In other words, it does not solve what's known as the "colored function" problem.
Regarding Swing, virtual threads are "just" threads so no reason they (and structured concurrency) can't be used.
reply
So does Java provide an API for continuations or just the virtual threads hidden behind the threading API? You can't use threads to wait for something on the UI thread (which is why e.g. SwingWorker exists), but you can with await.
reply
The colorless functions approach has well-known disadvantages though, including providing less control and making interop a pain. It isn't like one approach is the correct one and another is a mistake.
reply