当前位置: 首页 > 面试题库 >

是否可以对实例初始化进行重新排序并分配给共享变量?

宫瀚
2023-03-14
问题内容

我读的是一篇文章,实际上是关于双重检查锁定的,但是我为示例中出现的代码中的一个更基本的失败而感到惊讶。在那里声明,实例的初始化(即,在构造函数返回之前发生的实例变量的写入)可能在将实例的引用写入共享变量
之后 重新排序(实例中的静态字段)。以下示例)。

使用以下定义的class
Foo,在执行一个线程而执行Foo.initFoo();另一个线程时System.out.println(Foo.foo.a);,是否可以打印第二个线程0(而不是1抛出NullPointerException),是否正确?

class Foo {
    public int a = 1;

    public static Foo foo;

    public static void initFoo() {
        foo = new Foo();
    }

    public static void thread1() {
        initFoo(); // Executed on one thread.
    }

    public static void thread2() {
        System.out.println(foo.a); // Executed on a different thread
    }
}

从我对Java内存模型(以及其他语言的内存模型)的了解中,实际上这并不令我感到惊讶,但是直觉非常强烈地投票赞成这是不可能的(可能是因为涉及对象初始化并且对象初始化似乎如此)在Java中是神圣的)。

是否可以在0没有第一个线程同步的情况下“修复”此代码(即,它将永远不会打印)?


问题答案:

调用foo = new Foo();涉及到一些操作,除非您引入适当的同步措施以防止同步,否则这些操作可能会重新排序:

  1. 为新对象分配内存
  2. 写入字段的默认值(a = 0
  3. 写入字段的初始值(a = 1
  4. 发布对新创建对象的引用

没有适当的同步,步骤3和步骤4可能会重新排序(请注意,步骤2必须在步骤4之前发生),尽管x86架构上的热点不太可能发生。

为防止这种情况,您有几种解决方案,例如:

  • 进入a决赛
  • 同步访问foo(使用同步的initAND getter)。

无需深入了解JLS#17,您可以阅读有关类初始化(强调我的意思)的JLS#12.4.1:

初始化代码不受限制的事实允许html" target="_blank">构建示例,在 示例中
,在评估其初始化表达式之前,当类变量的值仍具有其初始默认值时,就可以观察到该变量的值 ,但实际上这种示例很少见。(
这些示例也可以用于实例变量初始化
。)Java编程语言的全部功能在这些初始化程序中可用。程序员必须格外小心。这种功能给代码生成器带来了额外的负担,但是由于Java编程语言是并发的,因此无论如何都会出现这种负担。



 类似资料:
  • 问题内容: 什么时候实例变量被初始化?是在构造函数块完成之后还是之前? 考虑以下示例: 家长建设者 子init() 父Init() 儿童构造者 属性1:100 属性2:null 什么时候在堆中分配属性1和2的内存? 好奇地知道为什么属性2为NULL? 有设计上的缺陷吗? 问题答案: 什么时候在堆中分配属性1和2的内存? 整个对象的内存是在调用构造函数之前在调用运算符时分配的。在中为单个实例分配了内

  • 本文向大家介绍tensorflow 初始化未初始化的变量实例,包括了tensorflow 初始化未初始化的变量实例的使用技巧和注意事项,需要的朋友参考一下 今日在Stack Overflow上看到一个问如何只初始化未初始化的变量,有人提供了一个函数,特地粘贴过来共大家品鉴: 通过tf.global_variables()返回一个全局变量的列表global_vars, 然后以python列表解析式的

  • 问题内容: 直观上似乎很清楚,在Java中,实例变量初始化器是按照它们在类声明中出现的顺序执行的。 在我正在使用的JDK中,似乎确实是这种情况。例如,以下内容: 打印(换句话说,y选择的默认值z)。 实际可以保证此顺序吗?我一直在浏览JLS,找不到任何明确的确认。 问题答案: 是的。 se7 JLS在12.5执行部分中介绍了实例变量的初始化顺序: … 4.执行此类的实例初始值设定项和实例变量初始值

  • 问题内容: 在Java中,声明类级别的实例变量而不初始化它会消耗内存吗? 例如:如果不使用初始化内存,是否使用任何内存? 细节: 我有一个巨大的超类,许多不同的子类(不足以拥有自己的超类)扩展了。某些子类不会使用超类声明的每个原语。我可以简单地将这些原语保留为未初始化状态,而仅在必要的子类中对其进行初始化以节省内存吗? 问题答案: 类中定义的所有成员都具有默认值,即使您没有显式初始化它们也是如此,

  • 我做了一些挖掘,似乎在任何地方都找不到简单的答案,也许我找错了地方。我只想按文件的修改时间排序,从最旧到最新。这可能吗?

  • 场景:匹配算法已识别ID1,ID2已匹配。我需要对匹配做进一步的分析。为此,我需要减少输出中的行数并正确排序。 这个输入只是样本和子集。拥有数千条实际记录使这项任务变得困难。 输入: 预期产出: 我需要确保输出应该有ID,应该有ID1和ID2组合的不同记录,这仍然很好,因为我可以进行distinct和union。 棘手的部分是确保输出中的数据排序。我需要将相似的行按顺序排列。 示例: 111,22