While testing vmlens, a tool to find data races in java applications, on open source projects, I found the following 5 tricks how to make classes thread safe.
1) Declare immutable member variables as final
Always declare immutable member variables as final. This makes sure that your class behaves correctly independent on how it is used. Take for example the field fieldAccessor in the class java.lang.reflect.Field.
private FieldAccessor fieldAccessor;
private FieldAccessor getFieldAccessor(Object obj)
boolean ov = override;
FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor;
return (a != null) ? a : acquireFieldAccessor(ov);
Since it is not synchronized and not declared volatile, a thread reading this field might not see a completely initialized object as described in DoubleCheckedLocking But since the created object type sun.reflect.UnsafeQualifiedIntegerFieldAccessorImpl only uses final problem, there is no problem. Threads reading this field will always see a fully initialized object or null.
2) Create objects eagerly
Using final fields forces you to initialize your objects in the constructor. Lazy initialization of your objects on the other side is almost never a good idea in concurrent programs.
Take for example the old version from org.apache.commons.lang.StringEscapeUtils. It uses the lazy initialized class org.apache.commons.lang.Entities$LookupEntityMap:
This only works with locks or synchronization. Much better is the new version org.apache.commons.lang3.StringEscapeUtils witch eagerly creates the lookup tables and also uses a final field.
public static final CharSequenceTranslator ESCAPE_XML10 =
3) Use volatile for mutable boolean variables
Mutable boolean fields are often used for controlling the flow of your application. For example to control the life cycle of a thread the following pattern can be used:
private volatile boolean isWorking;
// do something
Use a volatile field to make the changes done in one thread visible in other threads.
4) Check 3rd party classes
A typical example for not doing so, is the use of the non thread safe java.util.date as member variable without synchronization. Therefore always check if the class is documented as thread safe. If not chances are high that it is not.
Like all other features of your application, concurrency must be tested. In my next Blog post I will write how to test concurrency. In the meanwhile you can give vmlens a trial, which helps you to detect data races during testing.