java - 构建器模式的线程安全实现

标签 java multithreading design-patterns

有一个article我在寻找 builder pattern 的良好实践时遇到的.

在文章中,作者提到了一些引起我注意的事情。该模式是线程安全的。

build() 方法的第一个变体是线程安全的:

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

然而,这个不是:

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

尽管如此,我认为更好的方法是在 setters 中抛出 IllegalStateException :

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

构造函数如下所示:

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

setter 是:

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

我的方法仍然是线程安全的吗?如果没有,为什么?以线程安全的方式实现构建器模式的最佳方法是什么?

最佳答案

您的提案是线程安全的,因为返回的 User 对象将具有合法范围内的值,而“坏”示例不能保证这一点。如果构建器具有非法值,您的示例确实返回 null 而不是抛出异常,这可能是也可能不是您想要的。

人们通常不想从多个线程访问构建器对象。然而,当这样做很容易时,最好使用线程安全代码,就像在本例中一样;我可以想象不寻常的情况,人们实际上希望构建器由多个线程填充。当然,在这些情况下,对构建器的访问需要正确同步,例如通过使用 volatile 变量。

关于java - 构建器模式的线程安全实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37399228/

相关文章:

c - TCP 套接字上的 select() 仅适用于第一个循环

c++ - 观察者设计模式及其他

简单 Java 程序的 Javascript 包装器

java - 双数返回 stackoverflow

java - 增强型 for 循环中局部变量的范围

c# - System.Configuration 的线程安全使用

java - 如何使用 Flex 对数据网格中的 dd/mm/yy 日期格式进行排序?

java - java中notifyAll后线程不打印所有内容

java - JUnit:另一种测试异常的模式

c++ - OOP:如何在父类(super class)中动态扩展函数