Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

3 Synchronization Idioms

DZone's Guide to

3 Synchronization Idioms

Understand Signal, Snapshot, and PutIfAbsent, three synchronization idioms in Java, and how they're useful.

· Java Zone
Free Resource

Make it happen: rapid app development on Kubernetes as a managed service.

While testing vmlens on open source projects, I found the following 3 synchronization idioms. Each synchronization idiom is useful for a specific access pattern:

Access pattern Synchronization idiom
All threads only read or write Signal
One thread reads and writes other only read Snapshot
All threads read, creating an object if it does not exist PutIfAbsent

Signal

Change the behavior of a thread based on an event in another thread.

Motivation

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.

Structure

volatile

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

See a consistent state of an object.

Motivation

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.

Structure

snapshot

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);
        }
    }
}

Taken from java.util.concurrent.CopyOnWriteArrayList. Comments are mine.

Put if absent

Intent

Get an object out of a map in a multithreaded environment. Create it if it does not exist.

Motivation

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.

Structure

putIfAbsent

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;
    }

Taken from sun.util.locale.provider.JRELocaleProviderAdapter. Comments are mine.

Conclusion

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 like vmlens to detect race conditions during development and testing.

Tutorial: WordPress as distributed microservices on Kubernetes.

Topics:
java ,concurency

Published at DZone with permission of Thomas Krieger, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}