简体   繁体   English

线程安全构建器模式

[英]Thread safe Builder Pattern

I want to make my Builder pattern as Thread safe But facing issues in that, below is my code:我想让我的 Builder 模式成为线程安全但面临的问题,下面是我的代码:

// 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:还有另一个名为 StudentReceiver.java 的 class 我正在使用多线程:

    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:主要的 class 下面是我调用这些方法的地方:

//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:我得到的 output 如下所示:

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

Why I am getting null here??为什么我在这里得到 null? May anyone explain and How to make Builder Pattern thread safe so that it can be used in multithreaaded environment.任何人都可以解释以及如何使 Builder Pattern 线程安全,以便它可以在多线程环境中使用。

Your Builder Pattern is not the problem here.您的构建器模式不是这里的问题。 The Constructor of StudentReceiver is. StudentReceiver的构造函数是。

Starting a Thread inside it without joing it there will lead to the object being assigned, possibly and probably before the Thread even started.在其中启动一个线程而不加入它会导致 object 被分配,可能而且可能在线程开始之前。 So the student Field will not be set for quite some time.所以在很长一段时间内都不会设置student字段。 So much time in fact, that executing the System.out.println(sr.getStudent());事实上,执行System.out.println(sr.getStudent());的时间太多了。 line right after the constructor will (very probably) receive null from getStundent() .构造函数之后的行将(很可能)从getStundent()接收null

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 .并且生成器 class 不应该是 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!免责声明:未经测试!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM