Java语言规范中静态初始化的线程安全保证

4
通常认为静态初始化是线程安全的,保证只会发生一次。但我很好奇语言规范确切地在哪里声明了不会出现可见性问题?这来自于http://www.ibm.com/developerworks/library/j-jtp03304/ “这个过程保证了当一个变量在由给定监视器保护的同步块中被一个线程写入,并且在由相同监视器保护的同步块中被另一个线程读取时,变量的写入将被读取线程看到。JMM在没有同步的情况下不会做出此保证。”
我从其他几个来源也读到了类似的内容。对于静态初始化,我们不使用任何同步。假设初始化资源是有效不可变的,并且我们从不对其进行写操作,则永远不会使用同步来访问它,并且不将其设置为易失性。那么,保证任何读取线程不会看到空指针或部分初始化对象的保证来自哪里呢?显然,由于它发生在加载期间,不存在另一个线程在之前读取该值并看到旧值的可能性,但是有什么保证可以确保初始化结果不会留在执行线程的本地内存中?我很好奇静态初始化为什么是安全的。

编辑:我了解静态初始化是线程安全的。问题是为什么以及有什么保证。


似乎是一个重复的问题,与https://dev59.com/k3NA5IYBdhLWcg3wpvpg相同。 - ursa
1
@ursa:我不这么认为——更普遍(且定义不清)的是“线程安全”。这个问题特别地谈论了类初始化和内存模型的交互。在那篇文章中,甚至没有出现“内存模型”一词。一个答案提到了“先行发生”,但没有解释为什么初始化在规范方面发生在其他任何事情之前。我认为这作为一个单独的问题很好。 - Jon Skeet
1个回答

8
我相信这实际上是 JLS 12.4.2 中类初始化规则的结果。这涉及在锁上进行同步,仅在执行静态初始化程序和字段初始化程序后才释放它。然后,该锁获取和释放会通过 JLS 17.4.4 影响线程模型中的“发生在”部分(我想是这样-我不是这方面的专家)。
请注意,12.4.2 指出:
“实现可以通过省略在第 1 步中获取锁(并在第 4/5 步中释放锁)来优化此过程,前提是它可以确定类的初始化已经完成,并且在进行优化时,就内存模型而言,如果获取锁,则仍存在所有“发生在”排序。”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接