- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
比我更了解 Java 内存模型的人可以证实我对以下代码已正确同步的理解吗?
class Foo {
private final Bar bar;
Foo() {
this.bar = new Bar(this);
}
}
class Bar {
private final Foo foo;
Bar(Foo foo) {
this.foo = foo;
}
}
我知道这段代码是正确的,但我还没有完成整个happens-before 数学运算。我确实找到了两个非正式的引用,表明这是合法的,但我有点担心完全依赖它们:
The usage model for final fields is a simple one: Set the final fields for an object in that object's constructor; and do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields. It will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are. [The Java® Language Specification: Java SE 7 Edition, section 17.5]
另一个引用:
What does it mean for an object to be properly constructed? It simply means that no reference to the object being constructed is allowed to "escape" during construction. (See Safe Construction Techniques for examples.) In other words, do not place a reference to the object being constructed anywhere where another thread might be able to see it; do not assign it to a static field, do not register it as a listener with any other object, and so on. These tasks should be done after the constructor completes, not in the constructor. [JSR 133 (Java Memory Model) FAQ, "How do final fields work under the new JMM?"]
最佳答案
是的,它是安全的。您的代码不会引入数据竞争。因此,它已正确同步。这两个类的所有对象在完全初始化状态下对访问这些对象的任何线程都是可见的。
对于您的示例,这相当 straight-forward to derive formally :
对于正在构建线程的线程,所有观察到的字段值都需要与程序顺序保持一致。对于这种线程内一致性,在构造Bar
时,传递的Foo
值被正确地观察到并且永远不会null
。 (这可能看起来微不足道,但内存模型也调节“单线程”内存排序。)
对于获取 Foo
实例的任何线程,其引用的 Bar
值只能通过 final
读取 field 。这在读取 Foo
对象的地址和取消引用指向 Bar
实例的对象字段之间引入了解引用顺序。 p>
如果另一个线程因此能够完全观察到 Foo
实例(在形式上,存在一个内存链),则该线程保证观察到这个 Foo
完全构造,这意味着它的 Bar
字段包含一个完全初始化的值。
请注意,如果实例只能通过 Foo
读取,则 Bar
实例的字段本身是 final
甚至都没有关系。添加修饰符并没有什么坏处,而且可以更好地记录意图,因此您应该添加它。但是,就内存模型而言,即使没有它你也会没事的。
请注意,您引用的 JSR-133 说明书仅描述了内存模型的实现,而不是内存模型本身。在很多方面,它过于严格。有一天,OpenJDK 可能不再与此实现保持一致,而是实现一个不那么严格但仍能满足正式要求的模型。 永远不要针对实现进行编码,始终针对规范进行编码!例如,不要依赖于构造函数之后放置的内存屏障,HotSpot 或多或少就是这样实现它的。这些东西不能保证保留,甚至可能因不同的硬件架构而有所不同。
你不应该让 this
从构造函数中引用 escape 的引用规则也太狭隘了。你不应该让它逃逸到另一个线程。例如,如果您将它交给一个虚拟分派(dispatch)的方法,您将无法再控制实例的最终位置。因此,这是一个非常糟糕的做法!但是,实际上不会分派(dispatch)构造函数,您可以按照您描述的方式安全地创建循环引用。 (我假设您可以控制 Bar
及其 future 的变化。在共享代码库中,您应该严格记录 Bar
的构造函数不得让引用遗漏出。)
关于Java 内存模型 : Is it safe to create a cyclical reference graph of final instance fields, 全部在同一个线程中分配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29271194/
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 5 年前。 Improve
我有一个 mysql 表,其中包含一个名为“id”、“name”和“number”的字段。 每一行的字段'number',都有一个数字。 id name number 1 test 30
我需要获得两个字段之间的最大和最小值。我将 JPA 2.1 与 EclipsLink 结合使用。 这是我的简化查询: SELECT GREATEST(c.min, mc.max), LEAST(c.m
我想知道是否可以询问具有相同字段名称的多个表,并且只写入一次询问的值。可能是为了避免裁员。 例如: SELECT * FROM table WHERE Table1.Status AND Ta
我想知道如何以负增量更新字段,但如果新值小于 1,则删除该行? 是否可以在 case 或 if/else block 中放置和更新语句? 目前我正在执行一个 select 语句来获取当前值,然后使用
嗨,我一直在寻找 secnhatouch 字段的 readOnly 属性,但没有找到它......有人可以帮助我解决这个问题吗 { xtype: 'textfield
SQL Server 2005 报告服务。 我想在报告文本框中使用以下内容: =IIF(IsNothing(Fields!Certification.Value), "", "Certs: "
考虑下表: un_id avl_id avl_date avl_status 1738 6377398 2011-03-10 unavailable 1738 6377399
鉴于集合将包含 50 多万份文档,每个文档都有最大数量的字段(如选项 a 所示)处理可能为空/稀疏的字段的最佳实践是什么? a)将每个具有相同字段和空字段的文档保存为 null 是否更好? { "
尝试开始使用 apioto http://apiato.io/A.getting-started/installation/ 如果我尝试测试 http://api.apiato.dev/registe
我在教程中找不到这两个指令之间的区别。 th:field="${something}"和 th:field="*{something}" 谁能告诉我一些例子? 最佳答案 Reference site
在 MongoDb 中 - 如果我的字段并不总是包含值 - 更好的做法是:在所有记录中保留相同的字段,即使有时这些字段为空或根本不创建这些字段? 10 倍! 最佳答案 字段会占用键的磁盘空间,即使没有
如何使用 factory-boy 定义依赖于其他字段的字段? 例如,我想定义一个 email这取决于 first name和 last name的 User . 我尝试使用 post_generati
嘿嘿, 我遇到了以下问题:我尝试阻止用户为“用户名”和“电子邮件”字段选择相同的值。我正在使用 jquery 表单验证插件 (http://bassistance.de/jquery-plugins/
在性能方面,哪个更适合使用? ...关于可读性/可理解性? ...关于公认的标准? SELECT * FROM Wherever WHERE Greeting IN ('hello', 'hi', '
我想知道使用 this 和 super 访问父类字段的区别。 我们有以下名为 ListItem 的抽象类,它扩展了 Node 类。 public abstract class ListItem {
假设 this 是一个指针,(2) 和 (3) 行如何在下面的 C++ 类中编译,所以应该需要 -> 符号来访问字段(如 (1) 行所示)? ( Source ) #include #include
我想更好地理解通过单独使用 this.field 和 field 来引用类字段有什么区别 this.integerField = 5; 和 integerField = 5; 最佳答案 this 关键
问题:我有一张库存表,还有一张列出正在拍卖的元素的表格。我想要一个别名字段(“isAuction”)来表示具有库存库存编号的项目是否存在于拍卖项目表中。 我写了以下查询: SELECT FROM in
如果我将包含多个字段的文档添加到 Elasticsearch 索引,当我在 Kibana 中查看它时,我每次都会得到相同的字段两次。其中之一将被称为 some_field 另一个将被调用 some_f
我是一名优秀的程序员,十分优秀!