有一个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/