Content
The reason the tweaks are at the OS level is because, apparently, Loom-enabled JVMs already scale up to that level without needing any tuning. But if you try that in C++ you’re going to die very quickly. Also tickled to see my erlang 1M comet blog post referenced. TCP is rarely used alone now, it usually comes with SSL.
- All the 1_000 thread started nearly simultaneously, from what I could see in the output, and the total time was almost 15 seconds.
- The reason I’m so excited about Project Loom is that finally, we do not have to think about threads.
- If fibers are represented by the Fiber class, the underlying Thread instance would be accessible to code running in a fiber (e.g. with Thread.currentThread or Thread.sleep), which seems inadvisable.
- The virtual threads play an important role in serving concurrent requests from users and other applications.
Not all these will be gone with Project Loom , but for sure we’ll have to rethink our approach to concurrency in a number of places. There was also this rather obscure many-to-many model, in which case you had multiple user threads, typically a smaller number of kernel threads, and the JVM was doing mapping between all of these. With that model, every single time you create a user thread in your JVM, it actually creates a kernel thread. There is one-to-one mapping, which means effectively, if you create 100 threads, in the JVM you create 100 kernel resources, 100 kernel threads that are managed by the kernel itself.
Thread Pools are No Longer Needed
Handling 5M connections is great unless it takes a long time to reach that level of connectivity and you are depending on it. If a developer can write “regular” non-re-entrant Java code and still get the concurrent connections? The client Java process used 2.8 GB of committed resident memory and 8.9 GB of virtual memory. After running for 34.88m, it used 25m19s of CPU time.
The ability to interrupt a fiber or a virtual thread is crucial when writing concurrent code. Quite often, we are no longer interested in the result of a computation, maybe because of a timeout or because another one completed faster. We’ll still use the Scala programming language so that we vary only one component of the implementation, which should make the comparison easier.
Raft is a single, specific use-case that doesn’t use both Loom’s and ZIO capabilities to their full extent. Where the UIO type by definition represents a computation where all errors are handled. Exceptions might still occur—but they are then considered defects in the implementation, or fatal errors (we can always divide by 0!). Hence the expectation is included in the signature, and upon normal usage of ZIO’s API, the compiler will verify that we return the correct type.
JMeter + Loom experiment
Suppose we’re trying to test the correctness of a buggy version of Guava’s Suppliers.memoize function. He has a way of explaining even the most complex concepts in a way even I can understand lol. R2DBC SPI is not intended for direct usage but rather to be consumed through a client library. Dr Heinz Kabutz has programmed significant portions of several large Java applications and has taught Java to thousands of professional programmers.
Being an incubator feature, this might go through further changes during stabilization. Another common use case is parallel processing or multi-threading, where you might split a task into subtasks across multiple threads. Here you have to write solutions to avoid data corruption and data races. In some cases, you must also ensure thread synchronization when executing a parallel task distributed over multiple threads. The implementation becomes even more fragile and puts a lot more responsibility on the developer to ensure there are no issues like thread leaks and cancellation delays.
The only thing these kernel threads are doing is actually just scheduling, or going to sleep, but before they do it, they schedule themselves to be woken up after a certain time. Technically, this particular example could easily be implemented with just a scheduled ExecutorService, having a bunch of threads and 1 million tasks submitted to that executor. It’s just that java project loom the API finally allows us to build in a much different, much easier way. In terms of basic capabilities, fibers must run an arbitrary piece of Java code, concurrently with other threads , and allow the user to await their termination, namely, join them. Obviously, there must be mechanisms for suspending and resuming fibers, similar to LockSupport’s park/unpark.
Additionally, exceptions, stack traces, debugging tools, and other existing tools work out of the box, no need to worry about callbacks, chains of flow calls and observers, use some specific IO or concurrency library/API, etc. However, it turns out, first of all, it’s very easy with that tool to show you the actual Java threads. Rather than showing a single Java process, you see all Java threads in the output.
(Every active virtual thread has a ‘carrier’ platform thread). The trick virtual threads use to achieve their performance gain is to temporarily detach and park a virtual thread whenever it is blocked, so the same platform thread can be used to run another virtual thread. Blocking operations include a) I/O, b) when a thread is explicitly put to sleep, and c) when a thread enters a synchronized block. If the code that’s executing is short lived / runs fast, then this isn’t an issue – no changes to your code are needed. However, if you have code containing a synchronized block that performs a potentially slower blocking operation then this will continue to limit your application throughput because you’ll be tying up one of your platform threads. It won’t be any worse than before, but you won’t be taking full advantage of virtual threads.
Project Loom: Fibers and Continuations for the Java Virtual Machine
Testing also gets us only that far, it might show that in some scenarios the code behaves properly, but that’s no guarantee that race conditions or deadlocks won’t happen. Despite being a prime example of a distributed algorithm, there isn’t that much concurrency in Raft. For sure, there are multiple nodes running in parallel and exchanging messages, but this happens on separate nodes. As far as a single node is concerned, especially in our event-driven, actor-like implementation, concurrency is reduced—on purpose—to a minimum. As the suspension of a continuation would also require it to be stored in a call stack so it can be resumed in the same order, it becomes a costly process. To cater to that, the project Loom also aims to add lightweight stack retrieval while resuming the continuation.
With fibers, the two different uses would need to be clearly separated, as now a thread-local over possibly millions of threads is not a good approximation of processor-local data at all. If fibers are represented by Threads, then some changes would need to be made to such striped data structures. In any event, it is expected that the addition of fibers would necessitate adding an explicit API for accessing processor identity, whether precisely or approximately.
Carrier Thread
StructuredExecutor is a new tool introduced by project Loom which allows to show the ownership of the created virtual threads to this specific job in diagnostic tools. But note that it’s close() won’t wait for the completion but rather requires the owner to do this before closing, throwing an exception if the developer failed to do so. In response to these drawbacks, many asynchronous libraries have emerged in recent years, for example using CompletableFuture.
The points at which interruption might happen are also quite different. In ZIO, each time we sequence two effects , we create a potential interruption point. You can opt out of automatic supervision, but if you stick to defaults, it’s simply not possible to use the API incorrectly . With Loom, you have to make additional effort to ensure that no threads leak. Plus, you might need to wrap the low-level API, just as we did using the Loom class.
True for most languages but not once C gets involved. I don’t know to what extent you could “fix” C programs at the compiler level https://globalcloudteam.com/ to respect that invariant, even if you have LLVM bitcode. But at least the one-compiler aspect is not getting in the way.
@Holger – Eric seems “miffed” that the LOOM team have not responded directly to his posting on the developer list. Connect and share knowledge within a single location that is structured and easy to search. The Little Looms newsletter is tailored to the small-loom weaver, with projects, instruction, and inspiration to help you build skills and confidence. I loved the felt eyes but tested a few options for the rest of the face.
Problems and Limitations – Unsupported APIs
Another possible solution is the use of asynchronous concurrent APIs. CompletableFuture and RxJava are quite commonly used APIs, to name a few. As for the Loom project and its future, we think that virtual threads bring a new solution to the JVM which avoids the problems when using platform threads and also the problems with existing alternatives.
Loom expressjs
Although it’s a goal for Project Loom to allow pluggable schedulers with fibers,ForkJoinPoolin asynchronous mode will be used as the default scheduler. Java relies on OS implementation of continuations includes the native call stack along with Java’s call stack, it results in a heavy footprint. Project Loom is an attempt by the OpenJDK community to introduce a lightweight concurrency construct to Java.
What Loom Addresses
They promise increased throughput for apps whose performance is limited by blocking I/O, by making more effective use of O/S , maximising the available hardware resources. They achieve this by effectively multiplexing the use of O/S threads. For production apps, adoption of virtual threads is best deferred until after they have been finalised and become GA in a future version of Java.
If you’re somehow dealing with this scale, I doubt you’ll be stuck with pure legacy IP addressing. With a maximum of 64k TCP connections per single server IP, you need 77 different IP on the server side. Convenient polymorphism over exceptions is something I would very much like to see in Java, but it’s a separate topic. Given that structured concurrency is normally used with things that can fail, and whose failures must be handled, I hope you’ll find that the use of checked exceptions is not onerous at all. If we’re mistaken, we can consider solutions during the incubation period.
Adopting the use of virtual threads will therefore require using one or more of the above APIs. Library and framework developers are likely to make the heaviest use of these new APIs, rather than application developers, particularly the ones provided by the Thread class. With the recap out of the way, let’s get back to covering the cases where we may need to change existing code to take full advantage of the promise of virtual threads, covering both the why and the how.
Checking if the site connection is secure
Secondly, for some resources using a more specialised type of object pool is a better choice than directly using an ExecutorService , as it can provide a higher-level API and additional features. For example, capping the number of connections to a relational database is best implemented using a connection pool as it provides additional features such as a connection factory, connection validation, dynamic resizing, eviction etc. Virtual threads are several orders of magnitude cheaper to use than platform threads, in terms of their resource usage.
But, even if that were a win experienced developers are a rare and expensive commodity; the heart of scalability is really financial. Every test uses a thread group duration of 5 mins and each configuration is executed 3 times to ignore any potential outlier. The JMeter team has also discussed some alternatives in the past as well. For instance, they have explored using Kotlin coroutines. This does not only reduce resource consumption allowing to generate more load from the same hardware but also keeps all the benefits of the existing Java Thread model . Learn what are the pros and cons of using Project Loom to see if it’s desirable to incorporate it in a project.

