【问题标题】:Partially constructed object部分构造的对象
【发布时间】:2012-08-14 13:36:08
【问题描述】:

如果一个对象在其初始化期间对其他线程可见(在进行初始化时可见但尚未完成),这是否可能?如果是,那么您能否举一个简单的例子来支持您的理由?

【问题讨论】:

标签: java


【解决方案1】:

这可以通过多种方式发生。

  • 您将对象传递给构造函数中的另一个线程,例如您在构造函数中启动一个线程。
  • 您将对象传递给另一个线程,但另一个线程看到旧的、未初始化的值,因为这些字段不是最终的或易失的,也不是在锁定或同步的块中访问的。其他字段不保证是线程安全的。

【讨论】:

  • 嗨!感谢您的回答。我对 volatile 变量有疑问,例如: volatile Pool pool = new Pool();如果 Pool 构造函数在初始化过程中抛出异常,那么池现在指向哪里'
  • @FinalIllusion 如果 Pool 构造函数抛出异常,则 Pool 引用将保持不变——它不会引用部分构造的对象。
  • @yshavit 你的意思是它仍然指向之前分配的实例?
  • 是的,完全正确 -- 或者为 null,如果引用以前为 null。
  • 如果你在构造函数的某个地方传递this 并抛出一个异常,你将得到一个部分构造的对象。 ;)
【解决方案2】:

最好的例子是臭名昭著的双重检查锁定习语。我将只从中提取与该论点相关的部分。拿这个代码:

public class Holder { public static File f; }

在线程 A 的某个地方你执行Holder.f = new File("path"); 和在线程 B 的其他地方你执行 File xxf = Holder.f; 并继续使用它。即使您阅读了对Holder.f 的引用,也无法保证File 实例的任何字段都将处于任何已定义的状态。您可以读取所有空值(零值、假值,取决于类型),甚至是非空值和空值的任何变态组合。

【讨论】:

  • 如果一个对象的构造函数设置了一个final字段来引用一个新构造的新写的持有者,该持有者从未通过任何其他方式暴露;对final 字段的引用的存储能否保证对对象内项目的所有写入都已完成?
  • 引用 JLS 17.5:“当另一个线程看到对象时,该线程将始终看到该对象的 final 字段的正确构造版本。它还将看到引用的任何对象或数组的版本由那些至少与final 字段一样最新的final 字段。”我认为这完全涵盖了您所询问的内容。
  • 谢谢。因此,如果创建一个对象的唯一目的是将对其的引用放入 final 字段中,并且如果它永远不会暴露给任何会在此之后修改它的东西,那么对象本身就不需要担心是否有任何它的字段是final。知道非常有用。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-29
  • 1970-01-01
相关资源
最近更新 更多