Testing for concurrency is not as straight forward as asserting for conditions
to be true
or false
. It requires a thorough understanding of concurrency as
well as the various possible bugs that mainfest in concurrent code.
TL;DR - read as much as you can on concurrency including existing tests for popular Java concurrent code from JDK and other open-source libraries. Utilize static code analyzers for detecting early bugs.
The first step towards testing for concurrency is to locate concurrent code. This is the easiest step in all other steps. Any occurrence of the code below suggests presence of concurrency:
extends Thread
implements Runnable // this may not for sure be concurrent
// keywords such as
synchronized
volatile
// usage of methods such as
.notify()
.notifyAll()
.wait()
.wait(...)
.interrupt()
.join()
.join(...)
.interrupted()
.sleep()
.yield()
// usage of classes/packages such as
java.util.concurrent
java.util.concurrent.Atomic
java.util.concurrent.locks
// usage of library classes like
com.google.common.util.concurrent.ServiceManager
The next step in testing for concurrency is to mark all your code with concurrency related annotations as specified in Java Concurrency in Practice book. The annotations available are:
-
NotThreadSafe
- The presence of this annotation indicates that the author believes the class is not thread-safe. The absence of this annotation does not indicate that the class is thread-safe, instead this annotation is for cases where a naïve assumption could be easily made that the class is thread-safe. In general, it is a bad plan to assume a class is thread safe without good reason. -
ThreadSafe
- The presence of this annotation indicates that the author believes the class to be thread-safe. As such, there should be no sequence of accessing the public methods or fields that could put an instance of this class into an invalid state, irrespective of any rearrangement of those operations by the Java Runtime and without introducing any requirements for synchronization or coordination by the caller/accessor. -
GuardedBy
- The specified lock that guards the annotated field or method. -
Immutable
- The presence of this annotation indicates that the author believes the class to be immutable and hence inherently thread-safe. An immutable class is one where the state of an instance cannot be seen to change.
There are many static code analyzers available that can help detect concurrency bugs such as:
If the code is properly annotated with the JCIP concurrency annotations then there are high chances that the static code analyzers will help detect the basic mistakes that occur with concurrency.
- Avoid using non-synchronized Java objects such as
java.text.SimpleDateFormat
,StringBuilder
without proper guards
This is the last piece in testing concurrent code. The following articles explain with code samples on how various concurrent code pieces have been tested. Another nice place to read is to go thorugh the JUnit tests written for popular libraries like Google Guava.
-
This article explains with sample code on how to test an atomic big-counter class.
-
This article samples code on how to test concurrent access to a BitSet.
-
This article explains how to test a unique ID generator for concurreny.
-
JUnit test for the Google Guava
ServiceManager
class -
Apache Harmony was on open-source implementation of JDK 5. It includes JUnit tests for classes like AtomicInteger , ConcurrentHashMap , ReentrantReadWriteLock , ExecutorsTest and more
-
ConcurrentUnit - an extension for JUnit helping with testing concurrent code
-
Java Concurrency in Practice - IMHO the best book on Java concurrency