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

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

问题描述

Goetz的 Java并发实践,第41页,提及引用可以在构建过程中逃逸。 不要这样做示例:

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 实例的事实。情况可以通过使用静态工厂方法(首先构造plain对象,然后注册监听器)而不是public构造函数(做所有的工作)来修复。本书继续:

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 引用转义,该对象将被视为未正确构建。

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.

我不太明白。如果发布是构造函数中的最后一个语句,那么之前没有完成所有的构造工作?那么这个 c>是如何生效的呢?显然有一些巫术之后,但什么?

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?

推荐答案

构造函数的结束是一个特殊的地方在并发,相对于最终字段。从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.

最终字段的使用模型是一个简单的
。为
中的对象的
构造函数中的对象设置最终字段。不要在正在构造的对象中写入引用
,在
中,另一个线程可以在对象的构造函数
完成之前看到
。如果是这样,那么
当对象被另一个
线程看到时,该线程将总是看到
正确构造的版本的
对象的最后字段。它将
也看到由最终字段
引用的任何对象或
数组的版本,它们至少与
最后字段一样是最新的。

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.

换句话说,如果检查在另一个线程中的对象,你的监听器可能会看到final字段及其默认值。如果侦听器注册在构造函数完成后发生,则不会发生这种情况。

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天全站免登陆