core.async and Virtual Threads
core.async 1.9.829-alpha2 is now available, which adds support for Java virtual threads ( ASYNC-262 ). Threads must block while waiting on I/O operations to complete. "Parking" allows the platform to unmount and free the underlying thread resource while waiting. This allows users to write "normal" straight line code (without callbacks) while consuming fewer platform resources. Clojure core.async go blocks until now used an analyzer to rewrite code with inversion of control specifically for channel parking operations (the ! async ops like >! ). Other blocking operations ( !! channel ops or arbitrary I/O ops) are not allowed. Since Java 21, virtual threads implement I/O parking in the Java platform itself - that capability is a superset of what go blocks provide by supporting all blocking I/O operations. Because virtual threads are a superset of go block capabilities, go blocks can now be reimplemented using virtual threads without changing their semantics. Using virtual threads This release reimplements go blocks using virtual threads when available (Java 21+). go blocks retain their existing semantics (! channel ops park, blocking I/O not allowed) but do not require loading or running the analyzer. core.async is faster to load (when using Clojure >= 1.12.3) and faster to compile go blocks (no IOC). No code or configuration changes are required. io-thread io-thread was added in a previous core.async release and is a new execution context for running both channel operations (parking or blocking) and blocking I/O operations (which are not supported in go). Since alpha2, io-thread blocks

core.async 1.9.829-alpha2 has been released, introducing support for Java virtual threads (ASYNC-262). This update enhances the way Clojure handles concurrency, particularly for I/O operations, by leveraging the platform's capabilities to optimize resource usage.
Traditionally, threads must block while waiting for I/O operations to complete. This blocking can lead to resource inefficiency, as the underlying thread remains active even when it's not performing any work. To address this, the concept of "parking" allows the platform to unmount and free the thread resource during waiting periods. This enables developers to write straightforward, linear code without callbacks, while consuming fewer resources.
Prior to this release, Clojure's core.async go blocks utilized an analyzer to rewrite code with inversion of control (IOC) specifically for channel parking operations, such as the `!` async operations like `>!`. However, other blocking operations, such as `!!` channel ops or arbitrary I/O ops, were not supported. With Java 21, virtual threads now implement I/O parking natively, offering a superset of the functionality provided by go blocks. This means that go blocks can now be reimplemented using virtual threads without altering their semantics.
The core.async 1.9.829-alpha2 release reimplements go blocks using virtual threads when available (Java 21+). These go blocks maintain their original behavior, with `!` channel ops still parking and blocking I/O operations not permitted. Crucially, this change eliminates the need for loading or running the analyzer, resulting in faster loading times (especially with Clojure ≥ 1.12.3) and quicker compilation of go blocks. Importantly, no code or configuration changes are necessary for users to benefit from this update.
In addition to go blocks, core.async introduced `io-thread` in a previous release as a new execution context for running both channel operations (parking or blocking) and blocking I/O operations, which were not supported in go blocks. Since alpha2, `io-thread` also runs in virtual threads, further enhancing performance and resource efficiency.
To manage virtual thread usage, a new system property `clojure.core.async.vthreads` has been added. The possible values are:
- (unset, default): core.async will opportunistically use virtual threads when available (≥ Java 21) and fall back to the old analyzer implementation if not. `io-thread` and `:io` thread pools will run on platform threads if virtual threads are unavailable.
- `true`: Enforces the use of virtual threads for all threading operations.
- `false`: Disables virtual threads and uses the old analyzer implementation.
This release streamlines core.async's approach to concurrency, making it more efficient and compatible with modern Java versions. By leveraging virtual threads, developers can write cleaner, more resource-friendly code without compromising on performance. The seamless integration of virtual threads into core.async's existing architecture ensures that users can take advantage of these improvements without needing to modify their code.










