All Articles

concurrency

Concurrency in Practice

An awesome book on concurrency that all Java programmers ought to read before embarking on anything more complicated than the primordial Hello World application. I cannot help but reiterate here an example on one of my favourite subjects, that of publication safety. A typical (yet unsafe) lazy initialisation is shown below:

public class LazyInitialization {
    private static Resource resource;

    public static Resource getInstance() {
        if (resource == null)
            resource = new Resource();
        return resource;
    }
}

There’s two issues with this approach. The first is easy to spot: if threads A and B call getInstance() at the same time, they may both see resource as null and both proceed in creating a Resource instance, hence ending up creating two different instances even though getInstance() is supposed to always return the one and the same instance.

The second is much more subtle and has to do with publication. Suppose that thread A first invokes getInstance() and creates a Resource instance, then thread B sees that resource is non-null and returns the resource reference. B could observe however the write to the resource reference by A as occurring before writes to resource’s fields by Resource’s constructors! Hence, B could see a partially constructed Resource. One way this can be fixed is by making getInstance() synchronized. Another way is by changing the lazy initialization to eager:

public class LazyInitialization {
    private static Resource resource = new Resource();

    public static Resource getInstance() {
        return resource;
    }
}

Why does this work? Static initializers are run by JVM at class initialization time, i.e. before any thread has the chance to use the class. In addition, JVM acquires a lock while doing so, and this same lock is acquired by every thread at least once to ensure that the class has been loaded, therefore all memory writes made during initialization are visible to all threads. Any subsequent modifications will need to be synchronized of course between readers and writers, unless Resource is immutable.