java - 为什么 Java Bean 模式不是线程安全的

标签 java constructor javabeans builder

Joshua Bloch 在 Effective Java,第 2 版中指出:

伸缩构造函数模式的另一种选择是 JavaBean 模式,您可以在其中调用带有强制参数的构造函数,然后在之后调用任何可选的 setter :

Pizza pizza = new Pizza(12);
pizza.setCheese(true);
pizza.setPepperoni(true);
pizza.setBacon(true);

这里的问题是,因为对象是通过多次调用创建的,它可能在构建过程中处于不一致状态。这也需要付出很多额外的努力来确保线程安全。

我的问题:- 上面的代码不是线程安全的吗?我是否缺少任何基本的东西?

提前致谢

苏里亚

最佳答案

您向我们展示的代码仅涉及一个线程,因此该代码的线程安全没有实际意义。

如果多个线程可以看到Pizza实例,那么有两件事需要担心:

  1. 在您完成初始化之前,另一个线程能否看到 Pizza 实例?

  2. 当另一个线程看到实例时,它会观察到正确的属性值吗?

第一个问题是在完成初始化之前不“发布”对另一个线程的引用。

第二个问题可以通过使用适当的同步机制来解决,以确保更改可见。这可以通过多种方式完成。例如:

  • 您可以将 getter 和 setter 声明为同步方法。
  • 您可以将保存属性值的(私有(private))变量声明为 volatile

请注意,JavaBean 模式并未规定 bean 的构造方式。在您的示例中,您使用无参数构造函数,然后使用 setter 设置字段。您还可以实现一个构造函数,它允许您传递为属性提供(非默认)初始值的参数。

This also requires a lot of extra effort to ensure thread safety

不是真的。在这种情况下,使 getter 和 setter 线程安全是一个小改动。例如:

public class Pizza {
     private boolean cheese;

     public synchronized /* added */ void setCheese(boolean cheese) {
         this.cheese = cheese;
     }

     public synchronized /* added */ boolean isCheese() {
         return cheese;
     }
}

关于java - 为什么 Java Bean 模式不是线程安全的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44345780/

相关文章:

javascript - WebDriver 下拉菜单不会保持打开状态

JavaScript 对象创建/关联性

java - 在构造函数中而不是在构造函数中加载数据

java - 相同的数据应用于相同类型的所有 Bean,同时创建具有不同数据的 Bean 列表

java - Tomcat 中 OpenCV 的 UnsatisfiedLinkError

java - 在 Linux (Ubuntu) 中禁用快捷键

c++ - 如何使用构造函数中的参数调用 C++ 中另一个类的构造函数?

java - 从不同的 Java 类访问 Java Bean

java - Java Bean 作为数据存储类是糟糕的设计吗?

Java Sprite 表渲染