5 ms·
How much old advice on Java concurrency will virtual threads change? I'm building a course for people who are new to Java concurrency and I've made the assumpt
by mattbee 3y ago
How much old advice on Java concurrency will virtual threads change?
I'm building a course for people who are new to Java concurrency and I've made the assumption that from September, you will almost always _choose_ virtual threads over platform threads. The default virtual thread management surely matches what most people want most of the time (1 worker thread per CPU core, virtual threads on top). It removes a lot of the old worries about management of thread pools and how OS thread implementation details "leak" into Java.
It's brought it much closer to how I'd written coaching material for multithreading in Go, but the Executor abstractions will still let Java programmers shift over from platform threads at their own pace.
- KRAKRISMOTT 3y agoOnly for IO bound tasks, if you are doing a compute bound task that needs to saturate all cores, I am not sure what benefits virtual threads would bring.
- cogman10 3y agoDepends a lot on what you are doing and if you need preemption. There's not a huge penalty for using a virtual thread for compute (Other than impacting IO bound tasks).
- PaulKeeble 3y agoThe trade off is going to remain the same for parallel algorithms, once saturated performance will gradually decline as swapping threads harms performance. Go for example exposes the CPU Core/thread count because unbounded performs worse even despite its apparently cheap virtual threads. I have tested this a number of times in Java and Go and the situation is similar you want to be using near the CPU count dependent on the algorithm and IO. It will be the same in Java with virtual thread, the cost of the threads will be lower but the optimal number likely wont change much.
- bcrosby95 3y agoIn Java, unless they changed something in the past ~6 months, virtual threads will not "swap out" a CPU bound task, you have to have some blocking, otherwise it will keep on chugging. Depending upon your POV this may be a positive or negative. You can get around it by manually inserting some sleeps() - note that yield() won't work (which is kinda unfortunate).
- deleted 3y ago[deleted]
- peterashford 3y agoDoes sleep(0) also work?
- riku_iki 3y ago> Only for IO bound tasks do you know any docs/examples how this can be integrated with current java io libraries?.
- invalidname 3y agoAt the moment (as far as I know), only for NETWORKING bound tasks. Not general IO. Java at the moment doesn't support asynchronous file IO, this makes some sense since async-io on Linux is a bit of a mess still in terms of stability and security (but it's getting there so fingers crossed...). E.g. I'm building an app that does a lot of file IO and I won't be using virtual threads. They would provide nothing for this particular use case.
- cogman10 3y agoWrangling executor services (practically) becomes an antipattern. Where old java you'd do a singleton threadpool, virtual thread java you'd pretty much never do that. In cases where you might be tempted to do that, the common fork join pool is likely the better choice. Locks become more relevant. Old java you might have limited concurrency using thread pool size. With virtual threads something like a blocking queue or semaphore is likely a better choice. Reactive java should be avoided (IMO). It was a decent choice for old java, for virtual thread java you get little benefits from it. This will probably change, but with old java `synchronized` was alright. Virtual thread java you want to avoid that. This likely won't change, ThreadLocalStorage is a bad idea with virtual threads, you almost certainly want to use ScopedValues instead. You should understand the implications of structured concurrency. It's not fully ready yet, but at very least the `try(var service = newVirtualThreadPoolExecutor)` does work (I believe) which will block until all tasks launched are completed. This is likely desirable but might be unexpected if you wanted to fire and forget something. Otherwise, I think all the old concurrency advice applies.
- clumsysmurf 3y ago> Reactive java should be avoided (IMO). It was a decent choice for old java, for virtual thread java you get little benefits from it. This is interesting, we used RxJava quite a bit on Android until Kotlin Coroutines made things a bit easier in that the code read more linearly and worked nicely with built in language features like exceptions for error handling. Just curious if you agree with this in Java, or had other reasons.
- vips7L 3y agoEven before the introduction of virtual threads RxJava should have been avoided. It colors your entire code base, prevents natural error handling, and quite frankly makes maintenance that much more complex. Obviously there’s a place for it, but every project I’ve been on that used it shouldn’t have.
- Alupis 3y ago
- clumsysmurf 3y agoNow would be a good time for an revised edition of JCIP (Java Concurrency in Practice).
- mattbee 3y agoFor sure, yes, it's from 2006! I didn't have that one to hand, but remember the O'Reilly "Java Threads" book from 1999 and >50% of that was still useful for bringing a younger colleague up to speed.
- dikei 3y agoSo I subscribe to the belief that a Java multi-thread application should have at least 2 pools: 1 bounded pool for CPU-heavy tasks and 1 unbounded pool for IO tasks. I'll probably change the IO-pool to using virtual threads now, while keeping the CPU-pool on real thread.
- NovaX 3y agoI don't think VTs should be used in practice until Java 22, when it is likely that synchronization (monitors) will be supported [1]. A lot of code may synchronize and be non-trivial to convert to a ReentrantLock, such as ConcurrentHashMap's computeIfAbsent. This can lead to surprising failures outside of the application author's control, such as [2]. Go was originally non-preemptive ("the loops problem"). This was changed in 2019 to preempt at safepoints [3]. The Java team will probably have to do this too [4], but similarly it is low on their priority list and requires feedback. java.util.concurrent is still the basis of good Java concurrency. Some external libraries for reactive or actors might become less popular, but they were always the minority. There will be some improvements with structured concurrency to make that a little bit easier, but the fundamental approach will remain the same. I think old advice will be relevant, except when it comes to thread pool sizing (which was always a black art). At best some over eager use of async will go away and we'll return to simpler blocking code. [1] https://github.com/openjdk/loom/commit/24e80bdee3eaf347f2eab1886be5b52a0185aae7 https://github.com/openjdk/loom/commit/24e80bdee3eaf347f2eab... [2] https://mail.openjdk.org/pipermail/loom-dev/2023-July/005990.html https://mail.openjdk.org/pipermail/loom-dev/2023-July/005990... [3] https://go.dev/src/runtime/preempt.go https://go.dev/src/runtime/preempt.go [4] https://github.com/openjdk/loom/tree/preempt-support https://github.com/openjdk/loom/tree/preempt-support [5] https://openjdk.org/jeps/453 https://openjdk.org/jeps/453
- jjtheblunt 3y agoWere original Java green threads preemptive (and at safepoints)?
- NovaX 3y agoIt is sad that Googling didn't find the answer by ChatGPT did. --- Here's an excerpt from the book "Java Threads" by Scott Oaks and Henry Wong, published by O'Reilly Media, which discusses green threads: "Green threads provide a thread abstraction to the application, allowing the programmer to write multithreaded programs without worrying about the underlying OS support. However, because they're implemented at the user level, they are not subject to preemptive multitasking by the underlying OS. Instead, they must voluntarily yield control to other threads. If a green thread fails to do this, it can effectively freeze all other green threads in the system." This excerpt supports the fact that green threads were not preemptive and relied on voluntary cooperation to switch control between threads.