什么是“未完全构造的对象"? [英] What is an "incompletely constructed object"?

查看:25
本文介绍了什么是“未完全构造的对象"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Goetz 的 Java 并发实践,第 41 页,提到了 this 参考如何施工时逃生.一个不要这样做"的例子:

Goetz's Java Concurrency in Practice, page 41, mentions how this reference can escape during construction. A "don't do this" example:

public class ThisEscape {
    public ThisEscape(EventSource source) {
        source.registerListener(
            new EventListener() {
                public void onEvent(Event e) {
                    doSomething(e);
                }
            });
    }
}

这里的 this 是通过 doSomething(e) 引用封闭的 ThisEscape 实例这一事实来转义"的.这种情况可以通过使用静态工厂方法(首先构造普通对象,然后注册侦听器)而不是公共构造函数(完成所有工作)来解决.本书继续:

Here this is "escaping" via the fact that doSomething(e) refers to the enclosing ThisEscape instance. The situation can be fixed by using static factory methods (first construct the plain object, then register the listener) instead of public constructors (doing all the work). The book goes on:

从其构造函数中发布对象可以发布未完全构造的对象.这是正确的即使发布是构造函数中的最后一条语句.如果在构造过程中 this 引用转义,则认为该对象未正确构造.em>

Publishing an object from within its constructor can publish an incompletely constructed object. This is true even if the publication is the last statement in the constructor. If the this reference escapes during construction, the object is considered not properly constructed.

我不太明白.如果发布是构造函数中的最后一条语句,那么在此之前不是所有的构造工作都已经完成了吗?为什么到时候 this 无效?显然在那之后有一些巫毒教,但什么?

I don't quite get this. If the publication is the last statement in the constructor, hasn't all the constructing work been done before that? How come is this not valid by then? Apparently there's some voodoo going on after that, but what?

推荐答案

就并发性而言,构造函数的末尾是一个特殊的地方,就 final 字段而言.来自 Java 语言规范的 第 17.5 节:

The end of a constructor is a special place in terms of concurrency, with respect to final fields. From section 17.5 of the Java Language Specification:

一个对象被认为是完全初始化时构造函数完成.一个线程只能看到一个对象的引用在该对象完全被初始化保证看到正确初始化的值对象的最终字段.

An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.

final 字段的使用模型是简单的一个.设置最终字段该对象中的一个对象构造函数.不写参考到正在构造的对象另一个线程可以看到它的地方在对象的构造函数之前完成的.如果遵循这个,那么当物体被另一个人看到时线程,该线程将始终看到正确构造的版本该对象的最终字段.它会另请参阅任何对象的版本或这些最终字段引用的数组至少与最终字段是.

The usage model for final fields is a simple one. Set the final fields for an object in that object's constructor. 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.

换句话说,如果您的侦听器检查另一个线程中的对象,则它最终可能会看到具有默认值的最终字段.如果在构造函数完成后注册侦听器,则不会发生这种情况.

In other words, your listener could end up seeing final fields with their default values if it examines the object in another thread. This wouldn't happen if listener registration happened after the constructor has completed.

就发生的事情而言,我怀疑在构造函数的最后有一个隐式内存屏障,确保所有线程看到"新数据;如果没有应用内存屏障,可能会出现问题.

In terms of what's going on, I suspect there's an implicit memory barrier at the very end of a constructor, making sure that all threads "see" the new data; without that memory barrier having been applied, there could be problems.

这篇关于什么是“未完全构造的对象"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆