6 ms·
This is a great writeup, and reignites my interest in Java. (I've long considered "Java Concurrency in Practice" to be the _best_ Java book ever written.) I ha
by ccooffee 4y ago
This is a great writeup, and reignites my interest in Java. (I've long considered "Java Concurrency in Practice" to be the _best_ Java book ever written.)
I haven't been able to figure out how the "unmount" of a virtual thread works. As stated in this article:
> Nearly all blocking points in the JDK have been adapted so that when encountering a blocking operation on a virtual thread, the virtual thread is unmounted from its carrier instead of blocking.
How would I implement this logic in my own libraries? The underlying JEP 425[0] doesn't seem to list any explicit APIs for that, but it does give other details not in the OP writeup.
[0] https://openjdk.org/jeps/425 https://openjdk.org/jeps/425
- rlawson 4y agoAgree - Java Concurrency in Practice was a revelation when it came out. Well the whole concurrent api by Dr. Lea made it all so much saner. Very excited for virtual threads!
- geodel 4y agoWell one way is to replace "synchronized" blocks with ReentrantLocks where ever you can.
- cvoss 4y agoI would guess that LockSupport.park() and friends have also been adapted to support virtual thread unmounting.
- ecshafer 4y agoJava Concurrency in Practice is a fantastic book. I had DL as a professor for about a half dozen courses in undergrad, including Concurrent and Parallel Programming. Absolutely fantastic professor, with a lot of insight into how parallel programming really works at the language level. One of the best courses I've taken.
- anonymousDan 4y agoYeah Java gets a lot of grief, but I learned a lot about concurrent programming from making sure I really understood every line of code in this book.
- vips7L 4y agoI’m honestly so envious you had him as a professor.
- Nzen 4y agoI don't know how they did it, but you could use that jep id as a query in the jdk issue tracker [0], and then use the issue tracker id to find the corresponding github issue [1]. (I had hoped for commits with that prefix, but there don't seem to be any for that issue.) [0] https://bugs.openjdk.org/browse/JDK-8277131?jql=issuetype%20%3D%20JEP%20AND%20text%20~%20%22425%22 https://bugs.openjdk.org/browse/JDK-8277131?jql=issuetype%20... [1] https://github.com/openjdk/jdk/pull/8787 https://github.com/openjdk/jdk/pull/8787
- chrisseaton 4y ago> I haven't been able to figure out how the "unmount" of a virtual thread works. The native stack is just memory like any other, pointed to by the stack pointer. You can unmount one stack and mount another by changing the stack pointer. You can also do it by copying the stack out to a backing store, and copying the new thread's stack back in. I think the JVM does the latter, but not an expert.
- galaxyLogic 4y agoSeems like a good development. I've been doing Node.js for last few years after letting go of Java. But there's something uneasy about async/await. For one thing it's difficult to debug how the async functions interact.
- lolive 4y agoDebugging asynchronicity is complex in any language, no? Blocking endpoints are mostly irrelevent because it alters the temporal flow of things, which makes your code executed in debug mode not 100% « isomorphic » with your code executed in run mode.
- dboreham 4y agoNo?
- invalidname 4y agoThat's seamless though. So if you have a failure you get a single stack trace that includes everything. In JS the debuggers sometimes glue stack traces together which works for basic stuff but incurs a major runtime overhead and doesn't work for production failures. Locally the concept of multi-threaded debugging is easier than async-await since a single flow typically maps to a single thread and you can just step over it. If something happens asynchronously it's just IO and you can ignore that part. As far as you're concerned it's just one thread that you're stepping over/into. Variable context, scope etc. are maintained the same and passed seamlessly.
- galaxyLogic 4y agoI'm trying to understand what exactly is different about debugging async/await vs. debugging threads. Isn't making an async-call the same as starting a new thread, from the programmer's point of view? In my environment the WebStorm debugger I can debug async-calls in which I have halted in the stack. But I can not inspect the variable-values in the earlier "trace" that started the async-call. Is it just a matter of debugger capabilities or is there something that makes thread-based debugging fundamentally less confusing? Ah maybe I get it. When starting an async-call to read a file for instance the value of variables is no longer available in the callback. Whereas in a (real) thread they are, because from my point of view the thread was simply "sleeping" while the IO was happening. When the IO is over I back in the same context except I now have the read file-contents available for my inspection. So, reading a file in a thread-based system does NOT require you to start a new thread, whereas in async-await you essentially do have to create a new async-context (which is like a new thread) to read a file. No?
- cypressious 4y agoDoes you library use any of the JDK's blocking APIs like Thread.sleep, Socket or FileInputStream directly or transitively? If so, it is already compatible. The only thing you should check is if you're using monitors for synchronization which are currently causing the carrier thread to get pinned. The recommendation is to use locks instead.
- woooooo 4y agoMonitors as in the synchronized keyword? Because that is kind of a big one.
- mike_hearn 4y agoYes but it only really matters if you're blocking on IO whilst inside a synchronized block. If you're using it to protect in-memory data structures then it's not a big deal.
- pron 4y ago> How would I implement this logic in my own libraries? There's no need to if your code is in Java. We had to change low-level I/O in the JDK because it drops down to native. That's not to say every Java library is virtual-thread-friendly. For one, there's the issue of pinning (see the JEP) that might require small changes (right now the problem is most common in JDBC drivers, but they're already working on addressing it). The bigger issue, mostly in low-level frameworks, is implicit assumptions about a small number of shared threads, whereas virtual threads are plentiful and are never pooled, so they're never shared. An example of such an issue is in Netty, where they allocate very large native buffers and cache them in ThreadLocals, which assumes that the number of threads is low, and that they're reused by lots of tasks.
- _benedict 4y agoConversely, some applications would like a leaky abstraction they have some control over. Some caching will likely remain beneficial to link to a carrier thread. As a member of the Cassandra community I’m super excited to get my hands on virtual threads come the next LTS (and Cassandra’s upgrade cycle), as it will permit us to solve many outstanding problems much more cheaply. I hope by then we’ll also have facilities for controlling the scheduling of virtual threads on carrier threads. I would rather not wait another LTS cycle to be able to make proper use of them.
- pron 4y agoLTS is a designation by our sales organisation for arbitrarily chosen versions so they can offer a support service for legacy codebases -- i.e. people willing to pay for the privilege of not getting new features [1]. Why anyone would wait for something intended for the sole purpose of not adding new features to get a new feature --and so enjoying the very worst of both worlds -- is beyond me. The development organisation has no consideration of support offerings. All releases are equal, and the assumption is that those who want new features obviously do not want LTS and vice-versa. Anyway, the mention of the perennially misunderstood Java LTS is a pet peeve of mine, so I'm sorry if this comment was overly aggressive. [1]: There are many legacy applications that aren't actively developed. They have no use for new features, and new features sometimes requires changing configurations -- a hassle they don't have the people to do. So LTS is a subscription service that allows them to get releases without new features so they can keep running legacy apps without much maintenance. It's a great service, but obviously the opposite of what actively maintained codebases want; for them we have the regular upgrade model.