Signal

Intent

Motivation

Structure

Change the behavior of a thread based on an event in another thread.In GUI Frameworks like swing the event thread handles all user events. Some events do not depend on the current state of other threads. An example is the cancel event for a long running operation. To notify worker threads an event handler uses the signal idiom.

The Signal idiom consists of a volatile field and at least on thread reading and one thread writing this field. The field must never be read and written in the same thread.

Sample Code

public class WorkerThread extends Thread { public volatile boolean canceled; public void run() { while( ! canceled ) { // do some work } } }

Snapshot

Intent

Motivation

Structure

See a consistent state of an object.A thread needs to make a long running computation with data which is potentially changed by other threads in the middle of the computation. An example is the deployment descriptor of a web application in a web server. Through automatic reloads the deployment descriptor might change in the middle of the processing of a web request. To see a consistent state the web request processing thread uses a snapshot of the deployment descriptor.

The Snapshot idiom consists of a class holding the current snapshot. A thread reading values gets the current snapshot and reads values from this snapshot. A thread writing values clones the current snapshot, changes this copy and set the clone as new current snapshot.

Sample Code

public class CopyOnWriteArrayList { final transient ReentrantLock lock = new ReentrantLock(); // usa a volatile field for the snapshot reference private transient volatile Object[] array; final Object[] getArray() { return array; } final void setArray(Object[] a) { array = a; } public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; // clone the object Object[] newElements = Arrays.copyOf(elements, len + 1); // change the local copy newElements[len] = e; // set the copy as new snapshot setArray(newElements); return true; } finally { lock.unlock(); } } public void forEach(Consumer action) { if (action == null) throw new NullPointerException(); // work with the current snapshot Object[] elements = getArray(); int len = elements.length; for (int i = 0; i < len; ++i) { @SuppressWarnings("unchecked") // all read operations are done on this snapshot E e = (E) elements[i]; action.accept(e); } } }

Put if absent

Intent

Motivation

Structure

Taken from java.util.concurrent.CopyOnWriteArrayList. Comments are mine.Get an object out of a map in a multithreaded environment. Create it if it does not exist.You have a map of objects which is accessed from many threads. Each thread behaves the same, checking if a value exists for a key, if not creating the value. You have many concurrent reads. A read should not be blocked by a write to a different key. For example in a web application the language specific formats are stored in a map, using the language as key. Each worker thread checks if the language specific formats are available in the map, if not the thread creates a new one.

A thread tries to get a value for a key calling get on a concurrent map. If the “get” method returns null it creates the missing value and calls putIfAbsent.

Sample Code

public Set getLanguageTagSet(String category) { // get the value Set tagset = langtagSets.get(category); // if value is null create one if (tagset == null) { tagset = createLanguageTagSet(category); // call putIfAbsent Set ts = langtagSets.putIfAbsent(category, tagset); // if putIfAbsent returns a value a other thread has created a new value in between if (ts != null) { tagset = ts; } } return tagset; }

Conclusion

Taken from sun.util.locale.provider.JRELocaleProviderAdapter. Comments are mine.Each synchronization idiom can only be used for a specific access pattern. Using it outside this access pattern will lead to race conditions in your application. Therefore always use a tool liketo detect race conditions during development and testing.