padawan
padawan

Reputation: 1315

Thread-safe implementation of builder pattern

There is an article that I came across while I was looking for a good practice of builder pattern.

In the article, the author mentions about something that drew my attention. the pattern being thread safe.

The first variation of build() method is thread-safe:

public User build() {
    User user = new user(this);
    if (user.getAge() > 120) {
        throw new IllegalStateException("Age out of range"); // thread-safe
    }
    return user;
}

Whereas, this one is not:

public User build() {
    if (age > 120) {
        throw new IllegalStateException("Age out of range"); // bad, not thread-safe
    }
    // This is the window of opportunity for a second thread to modify the value of age
    return new User(this);
}

Although, I think a better approach would be throwing IllegalStateException in the setters:

public User build() {
    User u = null;
    try {
        u = new User(this);
    }
    catch(IllegalStateException e){
        e.printStackTrace();
    }
    return u;
}

where the constructor looks like this:

private User(UserBuilder builder)
{
    setAge(builder.age);
}

and the setter is:

void setAge(int age) throws IllegalStateException {
    if(age > 0 && age < 120) this.age = age;
    else throw new IllegalStateException("Age out of range");
}

would my approach still be thread-safe? If not, why? And what is the best way to implement the builder pattern in a thread-safe way?

Upvotes: 1

Views: 2116

Answers (2)

Kezza
Kezza

Reputation: 746

From my experience there is no easy way to make the builder pattern thread safe assuming it's even possible for most implementations.

The nature of the builder pattern implies that values should be persisted between setup calls, right up to the build method is called and potentially beyond. Thus any thread sharing the builder could potentially change the values before the build method is called resulting in an incorrect result for all threads but the last.

I cannot be sure for your solution what the best approach is but I have successfully implemented builder patterns in a threaded client by introducing a factory to create a new builder every time the builder is needed and only using the builder as a local variable this keeping it on a separate stack.

I have found this to be the simplest, safest and most efficient method.

Remember keep it stupid simple, if you are jumping through hoops like in your example then I would treat this as a smell and consider a new approach.

Upvotes: 2

Warren Dew
Warren Dew

Reputation: 8938

Your proposal is thread safe in the sense that the User object returned will have a value in the legal range, which is not guaranteed with the "bad" example. Your example does return null rather than throwing an exception if the builder had an illegal value, which may or may not be what you want.

One would not normally want to access a builder object from multiple threads. However, it's always better to use thread safe code when doing so is easy as in this case; I can imagine unusual cases where one actually would want the builder to be populated by multiple threads. In those cases, of course, access to the builder would need to be properly synchronized, for example through the use of volatile variables.

Upvotes: 2

Related Questions