Search code examples
javaconstructorjavabeansbuilder

WhyJava Bean Pattern is not threadsafe


Joshua Bloch states in Effective Java, 2nd Edition:

One alternative you have to the Telescoping Constructor Pattern is the JavaBean Pattern where you call a constructor with the mandatory parameters and then call any optional setters after:

Pizza pizza = new Pizza(12);
pizza.setCheese(true);
pizza.setPepperoni(true);
pizza.setBacon(true);

The problem here is that because the object is created over several calls it may be in an inconsistent state partway through its construction. This also requires a lot of extra effort to ensure thread safety.

My Question:- Is above code not thread safe? Am I missing any basic thing?

Thanks in Advance,

Surya


Solution

  • The code that you have shown us involves only one thread, so thread-safety of this code is moot.

    If multiple threads could see the Pizza instance, then there are a couple of things to worry about:

    1. Can another thread see the Pizza instance before you have finished initializing it?

    2. When the other thread sees the instance, will it observe the correct values for the attributes?

    The first concern is addressed by not "publishing" the references to another thread until you have finished initializing it.

    The second one can be addressed by using an appropriate synchronization mechanism to ensure that the changes are visible. This could be done in a number of ways. For example:

    • You could declare the getters and setters as synchronized methods.
    • You could declare the (private) variables that hold the attribute values as volatile.

    Note that the JavaBean pattern doesn't prescribe how beans are constructed. In your example, you use a no-args constructor and then set fields using setters. You could also implement a constructor which allows you to pass arguments giving (non-default) initial values for properties.

    This also requires a lot of extra effort to ensure thread safety

    Not really. In this context, it is a small change to make the getters and setters thread-safe. For example:

    public class Pizza {
         private boolean cheese;
    
         public synchronized /* added */ void setCheese(boolean cheese) {
             this.cheese = cheese;
         }
    
         public synchronized /* added */ boolean isCheese() {
             return cheese;
         }
    }