How to Test If a Class Is Thread-Safe in Java
Learn how to test if a class is thread-safe in Java.
Join the DZone community and get the full member experience.Join For Free
Tests for thread safety differ from typical single-threaded tests. To test if a method is thread-safe we need to call the method in parallel from multiple threads. We need to do this for all potential thread interleavings. And afterward, we need to check if the result is correct.
Those three requirements for our test lead to a special type of tests for thread safety which differ from typical single-threaded tests. Since we want to test all thread interleavings our test must be repeatable and run automatically. And since the methods run in parallel the potential result is a combination of different outcomes.
You may also like: What Does Thread-Safety Mean in Java?
Let us look at an example to see how this looks in practice.
Suppose we want to test if the following class representing an Address is thread-safe. It offers one method to update the street and city, the method update and one method to read the complete Address, the method
I use volatile fields, line 2 through 4, to make sure that the threads always see the current values, as explained in greater detail here. You can download the source code of all examples from GitHub here.
Now, let us first see if the combination of
toString and update is thread-safe. Here is the test:
The test executes the two methods in parallel from two threads. To test all thread interleavings, we put the complete test in a while loop iterating over all thread interleavings using the class AllInterleavings from vmlens, line 7. To see if the class is thread-safe, we compare the result against the to potential outcomes, the value before the update and after the update, lines 17 through 20.
Running the test leads to the following error:
To see what went wrong, we look at the report vmlens generated:
The problem is that for one thread interleaving the thread with Thread id 30 first updates the street name and then the main thread, thread id 1, reads the street and city name. So, the main thread reads a partial updated address which leads to the error.
To make the address class thread-safe, we copy the address value every time we update the address. Here is a thread-safe implementation using this technique. It consists of two classes, an immutable value, and a mutable container.
First, the immutable value class:
Second is the mutable container class:
AddressUsingCopyOnWrite creates a new address value every time it updates the variable
addressValue. This makes sure that we always read a consistent address, either the value before or after the update.
If we run the test with those two classes, the test succeeds.
So far, we tested the combination of
update for thread safety. To test if a class is thread-safe, we need to test all combinations of modifying methods and all combinations of read-only methods together with modifying methods. So, for our example class, we need to test the following two combinations:
Since the combinations of read-only methods are automatically thread-safe, we do not need to test the combination of the method toString with itself.
So far, we used volatile fields to avoid data races. Let us see what happens when we use normal fields instead. So, in our thread-safe class
AddressUsingCopyOnWrite, we remove the volatile modifier and re-run our test. Now, vmlens reports a data race in the file target/interleave/issues.html
A data race is an access to a field where a thread might read a stale value. If the thread, indeed, reads a stale value depends on external factors like which optimizations the compiler is using or on which hardware architecture the JVM is running and on which cores the threads are running. To make it possible to always detect such a data race independent of those external factors, vmlens searches for data races in the execution trace of the test run. And if vmlens have found one as in the example, it reports them in the issue report.
Tests for thread safety differ from typical single-threaded tests. To test if the combination of two methods, a and b, is thread-safe, call them from two different threads. Put the complete test in a while loop iterating over all thread interleavings with the help from the class
AllInterleavings from vmlens. Test if the result is either an after b or b after a. And to test if a class is a thread-safe, test all combinations of modifying methods and all combinations of read-only methods together with modifying methods.
Published at DZone with permission of Thomas Krieger, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.