Lakshyaveer Chaudhary
Lakshyaveer Chaudhary

Reputation: 29

Thread safe Builder Pattern

I want to make my Builder pattern as Thread safe But facing issues in that, below is my code:

// Server Side Code 
final class Student { 
  
    // final instance fields 
    private final int id; 
    private final String name; 
    private final String address; 
  
    public Student(Builder builder) 
    { 
        this.id = builder.id; 
        this.name = builder.name; 
        this.address = builder.address; 
    } 
  
    // Static class Builder 
    public static class Builder {
  
        /// instance fields 
        private int id; 
        private String name; 
        private String address; 
  
        public static Builder newInstance() 
        { 
            return new Builder(); 
        } 
  
        private Builder() {} 
  
        // Setter methods 
        public Builder setId(int id) 
        { 
            this.id = id; 
            return this; 
        } 
        public Builder setName(String name) 
        { 
            this.name = name; 
            return this; 
        } 
        public Builder setAddress(String address) 
        { 
            this.address = address; 
            return this; 
        } 
  
        // build method to deal with outer class 
        // to return outer instance 
        public Student build() 
        { 
            return new Student(this); 
        } 
    } 
  
    @Override
    public String toString() 
    { 
        return "id = " + this.id + ", name = " + this.name +  
                               ", address = " + this.address; 
    } 
} 
  


----------

There is another class named StudentReceiver.java in which I am using multithreading:

    class StudentReceiver {

    // volatile student instance to ensure visibility
    // of shared reference to immutable objects
    private volatile Student student;

    public StudentReceiver() throws InterruptedException {

        Thread t1 = new Thread(new Runnable() {
            public void run() {
                student = Student.Builder.newInstance().setId(1).setName("Ram").setAddress("Noida").build();
            }
        });

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                student = Student.Builder.newInstance().setId(2).setName("Shyam").setAddress("Delhi").build();
            }
        });

        t1.start();
        t2.start();
        //t1.join();
        //t2.join();
        
    }

    public Student getStudent() {
        return student;
    }
}


----------

Main class is below from where I am calling these methods:

//Driver class 
public class BuilderDemo { 
 public static void main(String args[]) throws InterruptedException 
 { 
     for(int i=0; i<10;i++)
     {
         StudentReceiver sr = new StudentReceiver();
         
         System.out.println(sr.getStudent());
     }
 } 
}


----------

The output I am getting is like below:

null
null
null
null
null
null
null
null
id = 1, name = Ram, address = Noida
null

Why I am getting null here?? May anyone explain and How to make Builder Pattern thread safe so that it can be used in multithreaaded environment.

Upvotes: 0

Views: 442

Answers (1)

Fildor
Fildor

Reputation: 16129

Your Builder Pattern is not the problem here. The Constructor of StudentReceiver is.

Starting a Thread inside it without joing it there will lead to the object being assigned, possibly and probably before the Thread even started. So the student Field will not be set for quite some time. So much time in fact, that executing the System.out.println(sr.getStudent()); line right after the constructor will (very probably) receive null from getStundent().

The fix would be to either:

  • Not use a separate Thread in the Constructor.
  • Or join the thread inside the Constructor ( which somewhat defeates the Thread's purpose ).

And the Builder class should not be static.

Here is an example of what I'd do:

public interface IBuilder
{
   IBuilder setId( int id );
   // ...
   Student build();
}

final class Student { 
  
    // final instance fields 
    private final int id; 
    // + other fields - left out for brevity
  
    private Student(Builder builder) 
    { 
        this.id = builder.id; 
        // + other fields
    } 

    private static Object builderLock = new Object();
    public static IBuilder getBuilder()
    {
        synchronized(builderLock)
        {
            return new Builder();
        }
    }
  
    // Static class Builder 
    public class Builder implements IBuilder {
  
        // instance fields 
        private int id = -1; 
        // ...  

        private Builder() {} 
  
        // Setter methods 
        public IBuilder setId(int id) { 
            this.id = id; 
            return this; 
        }

        public Student build() {
            return new Student(this);
        }
    }
}

Disclaimer: untested!

Upvotes: 1

Related Questions