Home > Programming > Series about Java Concurrency – Pt. 2

Series about Java Concurrency – Pt. 2

This post is a follow up to Series about Java Concurrency – Pt. 1, so be sure to read it before this one.

But now let us talk about the puzzle, shall we? Just by reading the source code it seems very reasonable that the program should just print out “[0, 1, 2, 3]”, as EntityManager is obviously thread save, and is lazily initialized in a synchronized block. However, if you run this program multiple times, you will most likely see it printing something different, like “[0]”. In fact, all one can say for sure about this program, is that it prints out a map that contains at least one element, and at most four elements from the set {0, 1, 2, 3}. Everything else depends on the mood of the JVM, the operation system, and the underlying hardware. So what’s wrong? The problem is, that if multiple threads access a shared resource, this resource has to be safely published unless it is immutable. One way to do so, is through a synchronized block where both writes and reads are guarded by the same object. The program above fails to do so here

            synchronized(this)

because this is a different object in every thread. Indeed, replacing the code above with

            synchronized(AllTheSameButDifferent.class)

makes our shiny little program print “[0, 1, 2, 3]” reliably. Still, locking on AllTheSameButDifferent.class might not be the best idea, as another, completely unrelated thread may acquire it too. If this thread happens to perform some lengthy computations while holding the lock, our program would be slowed down needlessly. So, locking on entityManager seems to be a better approach, but it’s still not ideal, as future versions of EntityManager (imagine for the moment that we are dealing with a library class) might use the same lock internally, which brings us down to basically the same reasoning as before. Thus I would rather recommend using

            synchronized(Action.class)

or even

            synchronized(entityMangerLock)

where entityMangerLock is defined in Action like this

private static final Object entityMangerLock = new Object();

Still, while all this reasoning about choosing the appropriate object for locking might very well be the right thing to do in another example, our problem has a solution that is much more elegant, as it makes the JVM to do everything for us. It relies on the fact, that classes are not initialized before they are used, and that class initialization is performed in a thread save manner automagically. You can find more about this in EffJava2 Item 71 as well as in JaCoP1. Here is how it looks like:

package at.lnet.puzzle;

import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;

public class AlwaysTheSameAndLazilyInitialized
{
    private static class EntityManager
    {
        private final Set<Integer> data = Collections.synchronizedSet(new TreeSet<Integer>());
        
        public void persist(final int value)
        {
            data.add(value);
        }
        
        public Set<Integer> getData()
        {
            return Collections.unmodifiableSet(data);
        }
    }
    
    private static class Holder
    {
        private static final EntityManager entityManager = new EntityManager();
    }
    
    private static EntityManager getEntityManager()
    {
        return Holder.entityManager;
    }
    
    private static class Action implements Runnable
    {
        private final int data;
        
        public Action(final int data)
        {
            this.data = data;
        }
        
        @Override
        public void run()
        {
            getEntityManager().persist(data);
        }
    }
    
    public static void main(final String[] args) throws InterruptedException
    {
        final int NTHREADS = 4;
        Thread[] threads = new Thread[NTHREADS];
        
        for(int i = 0; i != NTHREADS; ++i)
            threads[i] = new Thread(new Action(i));
        for(int i = 0; i != NTHREADS; ++i)
            threads[i].start();
        for(int i = 0; i != NTHREADS; ++i)
            threads[i].join();
        
        System.out.println(getEntityManager().getData());
    }
}

Note that this version is only 3 lines longer than the original puzzle, which is exactly the length of the convenience method

private static EntityManager getEntityManager()
{
    return Holder.entityManager;
}

that we could have omitted in theory. If you don’t believe that entityManager is in fact still lazily initialized, step through the program with a debugger.

Advertisements
Categories: Programming Tags: , ,
  1. May 23, 2011 at 19:28

    You’re essentially making EntityManager a singleton. So why not just go whole hog? Adding a private static final reference within EntityManager to itself, and a public static accessor to the instance. You wind up with less code, less objects, it’s lazily initialized, and a more understood pattern.

    Understanding full well the derided reputation of Singleton, in this case it seems appropriate.

    • May 23, 2011 at 20:50

      Considering only the code from above I fully agree: Merging EntityManager and Holder into one class, and moving getEntityManager() into EntityManager would in fact be more elegant with the same benefits; however, imagine for a moment, that EntityManger comes from a library or is an old legacy class we really don’t want to touch.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: