Five Ways to Update Fields in a Thread Safe Way: Part 1
The first part of detailed tutorials on how to update fields in a thread safe way in Java, along with examples of how they work and how to test them.
Join the DZone community and get the full member experience.
Join For FreeThere are five ways to update a field in Java in a thread safe way. But before we start, what do you have to look at? If you access a field from many threads, you must make sure that:
- Changes are made visible to all threads
- The value is not changed during the update by the other threads
- Threads that are reading do not see the inconsistent intermediate state
You can achieve this by one of the following 5 ways:
Volatile Field
When to Use?
You can use a volatile field when you have only one thread updating and many threads reading a single-valued field. Or you can use it when the writing threads do not read the field. You can use it only for single valued fields like boolean or int. If you want to update object graphs or collections, use copy on write, as described below, instead.
Example
The following example code shows a worker thread, which stops processing based on a volatile field. This makes it possible for other threads, like an event dispatching thread, to stop the worker thread.
public class WorkerThread extends Thread
{
private volatile boolean canceled = false;
public void cancelThread()
{
this.canceled = true;
}
@Override public void run()
{
while( ! canceled )
{
// Do Some Work
}
}
}
How Does it Work?
Declaring the field volatile makes changes made by one thread visible to all other threads. As a writing thread do not read the value, point b “the value is not changed during the update by the other thread” is fulfilled. Since the field is a single value point c “reading threads do not see inconsistent intermediate state” is also fulfilled.
How to Test?
By using vmlens, an Eclipse plugin to test multi-threaded software and to detect Java race conditions, we can find fields, which should be declared volatile. After declaring the field volatile, we can check in the “order of event” view of vmlens, that the field is correctly read and written:
Copy On Write
When to Use?
Use copy on write if you want to update a graph of objects or a collection, and the threads mostly read and only rarely update.
Example
The following shows the add and get Method from java.util.concurrent.CopyOnWriteArrayList:
private transient volatile Object[] array;
final Object[] getArray()
{
return array;
}
public boolean add(E e)
{
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements); return true; }
finally {
lock.unlock();
}
}
public E get(int index)
{
return get(getArray(), index);
}
How Does it Work?
Again the volatile declaration makes changes made by one thread visible to the other threads. By using a lock around the updating method, we make sure that the value is not changed during the updating process. Since we copy the data before changing it, reading threads do not see the inconsistent intermediate state.
How to Test?
We can test this by using a multithreaded test and adding a wait point inside vmlens at the read of the field.
Lock-Based Atomic Update
When to Use?
Use locks when updates and reads happen equally often. Use it until the lock becomes a bottleneck and you need the more performant solution compareAndSet, as described below.
Example
The following example shows a lock based counter:
public class LockBasedCounter {
private int i = 0;
public synchronized void addOne()
{
i++;
}
public synchronized int get()
{
return i;
}
}
How Does it Work?
The synchronize statements make sure that the changes made by one thread are seen by the other threads. Since only one thread can execute the methods protected by the lock at a given time, the value can not be changed during the update by another thread and the other threads cannot see an intermediate inconsistent state.
How to Test?
We can test this by using a multi-threaded test and adding a wait point at the updating method.
Conclusion
Which of the first 3 of 5 ways you use to update a field in a thread safe way depends on your performance and safety requirements. Independent of which way you use, you should test it. Read more about unit testing multi-threaded software with vmlens and concurrent-junit in a new way to junit test your multithreaded java code. If you have a question or remark please add a comment below, and stay tuned for part 2 tomorrow!
Published at DZone with permission of Thomas Krieger, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments