[Update: changed wording per comments to fix error.]

Dependency injection is pretty well established these days, with plenty of Inversion of Control containers available to manage your beans. I'm currently reading Java Concurrency in Practiceby Brian Goetz et al, which got me thinking about the thread-safety of large object graphs managed by IoC containers.

In most applications I've seen, the common usage pattern is to use dependency injection to wire up your object graph in one go when the application starts. After that the application uses the object graph, and effectively treats it as being immutable. For example, in an application for buying books we might have aBookStore object that is given aBookFinder so it can find whether a particular book is available. The BookFinder is created at the beginning of the application and never changes. It is common to code this using setter injection:

public class BookFinder {

    // BookFinder's business methods...

}

public class BookStore {
    private BookFinder bookFinder;

    public void setBookFinder(BookFinder bookFinder) {
        this.bookFinder = bookFinder;
    }

    // BookStore's business methods which use bookFinder...

}

The problem is that it's not clear that this code is thread-safe. Unless the container publishes theBookStore bean safely then there is no guarantee that other threads will see the value of the BookFinderbean. If this seems weird then that's because it is. To quoteJava Concurrency in Practice (p33): "In general, there isno guarantee that the reading thread will see a value written by another thread on a timely basis, or even at all."

Thankfully, this is easy to fix. We can mark thebookFinder instance as volatile to ensure its visibility to other threads:

public class BookStore {
    private volatile BookFinder bookFinder;

    public void setBookFinder(BookFinder bookFinder) {
        this.bookFinder = bookFinder;
    }

    // BookStore's business methods which use bookFinder...

}

Alternatively, we can use constructor injection andfinal fields. This works because the Java Memory Model makes special guarantees about the safety of final fields.

public class BookStore {
    private final BookFinder bookFinder;

    public BookStore(BookFinder bookFinder) {
        this.bookFinder = bookFinder;
    }

    // BookStore's business methods which use bookFinder...

}

The Future

So could the IoC container providers take steps to ensure that application developers don't have to worry about thread safety in wiring up object graphs? Possibly, although at the time of writing it is less than clear whether the popular containers do or not. Tim Peierls, one of the authors of Java Concurrency in Practice, wrote in a email to me that "Until it's proven safe, I have adopted a rule that all such setter-injected effectively immutable fields must be volatile." He also suggested marking the field with an annotation, such as @WriteOnce, so that when your container's behaviour is clarified it is easy to go through code and remove the volatile modifier.