Roman Sterlin
Roman Sterlin

Reputation: 1617

Builder design pattern, returns null in a multi threaded environment

I was reading about the pattern here:

https://www.geeksforgeeks.org/builder-pattern-in-java/

the last part demonstrates how to use the pattern, I tried to copy the code into my IDE & run it but it returns null,

the 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;
    }
}

// Client Side Code 
class StudentReceiver {

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

    public StudentReceiver() {

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

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

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

    public Student getStudent() {
        return student;
    }
}

// Driver class 
public class BuilderDemo {
    public static void main(String args[]) {
        StudentReceiver sr = new StudentReceiver();
        System.out.println("sr " + sr.getStudent());
    }
}

When I remove the threads and run it without them it works, anyone has an idea of why it returns null instead of one of the student objects ?

Upvotes: 1

Views: 594

Answers (1)

Yan Khonski
Yan Khonski

Reputation: 13103

In your code, main thread is executed before student receiver executes the code.

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

t1.start(); // It starts, but the runnable itself has not run yet!

So first you get the student which is null and print it in main, then StudentReceiver will initialize your student.

Advise, do not do it in real world tasks, but do it for learning!

Alternatively, you can wait until the user is initialized. This is one approach.

try {
    t1.join();
    t2.join();
} catch (Exception e) {
    throw new RuntimeException("Handle it properly.", e);
}

Upvotes: 2

Related Questions