#22 Understanding the LMAX Disruptor
Latest Spring Framework and Spring Boot releases. Let's talk about ThreadLocals. Unit Testing Log Messages. Mars in 4K.
Welcome to the twenty-second edition of the Dukesletter!
The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise.
— Edsger Dijkstra
The JDK team has announced that Records and Pattern matching for instanceof will be released as completed features in JDK 16!
Understanding the LMAX Disruptor
When you look for articles about concurrency best practices in Java you always reach to LMAX library and Martin Thompson.
Even if you don't develop applications for financial trading companies, the concepts behind LMAX apply to many problems with a high concurrency rate. You can minimize the number of objects shared between threads and use immutable data structures, but at some point you will need to communicate and synchronize them.
“Understanding the LMAX Disruptor” article talks about shared memory, cache lines, memory barriers, and why Java BlockingQueues native implementations are not enough in some scenarios. Finally explains how Disruptor can minimize these problems and how its queue implementation deals with concurrency problems.
If you want to learn how to write a Hello World application using LMAX, you can continue with “Concurrency with LMAX Disruptor – An Introduction” by Baeldung.
And remember, there is no point in using the most complex concurrency system if then your business logic implementation is suboptimal, wasting a lot of resources.
Spring Framework 5.2 and Spring Boot 2.3
Spring Framework 1.0 was launched 16 years ago, and it hasn't stopped adding features since then.
The core feature is the same: an IoC container. Everything that has been added is only functionalities to simplify its integration with the container.
Spring Framework has become more a platform than a framework, with a lot of subprojects orbiting around it.
Its maximum expression is Spring Boot, which proposes a totally opinionated way of working, and stronger integration of their libraries. Going off the proposed track has a high cost.
In “Spring Framework 5.2: Core Container Revisited”, Juergen Hoeller (the Spring Framework Lead) explains the new additions to the Container, and improvements in reactive support.
They are paving the way to support GraalVM. Spring does a lot of magic with reflection, contrary to GraalVM principles to compile statically the code. Quarkus and Micronaut have emerged as tough competition.
The Spring Boot project has moved to a 6-month release schedule and their latest release was released in May. Phil Webb explains in the following video its main news, highlighting its advanced capabilities managing docker image creation, and its better integration with Kubernetes implementing needed monitorization endpoints and graceful shutdown.
Let's talk about ThreadLocals
ThreadLocal is a powerful functionality provided by the JVM. Probably you have never used it directly, but it is widely used by different frameworks, like Spring or Hibernate. You can read “An Introduction to ThreadLocal” to learn more about it.
For me is like another global variable, but accessible only by one thread. All global variables should be treated with care, and ThreadLocal ones even more because depends on some context: the Thread where your code is executed.
Current CPU architectures provide us with more cores, not faster cores, and we need to make our code parallelizable.
ThreadPools, parallel Streams, and Reactive frameworks help us, but introduce one problem: sometimes you lose the control about where your code is executed. Different parts of your algorithm can be executed in different threads, making useless the ThreadLocal utility.
In “Let's talk about ThreadLocals”, Sergei Egorov explains this problem in the reactive world. He shows the problem with Reactor and RxJava, and the solution will not surprise you :)
The main problem is not to stop using ThreadLocal, is to discover if some library you depend on is using internally ThreadLocals.
Unit Testing Log Messages
When you are creating the tests for some code sometimes you have a problem: you don’t know how to assert that something has happened. Usually, because the inner tested code doesn’t return a value, is not configurable with a spy or has no side effects in the system (persist in a database or file).
Probably this code logs some message (which can be seen as a side effect), and this information can be used to verify that our code is working correctly in a test.
LogCaptor is a library that will enable you to easily capture logging entries for unit testing. The author of LogCaptor, Hakan Altındağ, introduces it in the following article: “Unit Testing Log Messages Made Easy”.
The whole utility implementation is just a single file, which delegates in the logging framework the logs capture in an in-memory list, and uses it to request for logged messages.
This is an example of how utilities do not need to be very complex to provide much value.
Reading from a program output is one of the recommended techniques to refactor legacy code when you don’t have good test coverage.
The "Golden Master" technique proposes to create a set of test which validates the existing console output. Once you have a comfortable coverage, you can refactor the code validating that the output is the same after each refactor step (the logic has not changed its behavior).
You can learn more about this technique practicing with the Trivia Kata.
Finally, in your applications, which criteria do you use to log information? In the following article Henrik Warne reflects about what is Good Logging. The discussion in Hacker News is also very interesting
If your application requires a high rate of logged messages and is executing an online process, you can have a problem because logging can consume time, increasing requests latency. To solve it, you can use an asynchronous logger.
Do you know what uses one of the asynchronous log implementations of Log4j? LMAX Disruptor! You can read more about it in its documentation.
Mars in 4K
Curiosity can only send data directly back to earth at 32 kilo-bits per second.
Instead, when the rover can connect to the Mars Reconnaissance Orbiter, we get more favourable speeds of 2 Megabytes per second.
If you think time zones are tough, imagine the day we get to Mars.