3 回答
TA贡献2041条经验 获得超4个赞
您使用的方法是线程安全的。由于您没有引用您正在谈论的声明,因此我无法直接解决它们。但是 Java 语言规范对此主题很清楚。
在第 17.5 节中,它描述了
final
字段还允许程序员在没有同步的情况下实现线程安全的不可变对象。线程安全的不可变对象被所有线程视为不可变的,即使使用数据竞争在线程之间传递对不可变对象的引用也是如此。这可以提供安全保证,防止错误或恶意代码滥用不可变类。必须正确使用 final 字段以提供不变性保证。当一个对象的构造函数完成时,它被认为是完全初始化的。只有在对象完全初始化后才能看到对对象的引用的线程可以保证看到该对象的最终字段的正确初始化值。
TA贡献1847条经验 获得超7个赞
我不认为“热心单身”这个名字是合理的。
类或接口 T 将在以下任何一项第一次出现之前立即初始化:
T
是一个类并T
创建了一个实例。由
static
声明的方法T
被调用。一个
static
场宣布T
分配。阿
static
通过声明字段T
的使用量和字段不是常量变量(§4.12.4)。
因此,初始化和实例化Singleton
将getInstance()
在第一次调用该方法时发生,或者,由于您创建了该字段public
,当该字段第一次被访问时,以先到者为准。但不是更早。换句话说,这个初始化已经和所有其他尝试执行延迟初始化的尝试一样懒惰。
此初始化的安全性由JLS §12.4.2, 详细初始化程序给出
对于每个类或接口
C
,都有一个唯一的初始化锁LC
。从C
到到的映射由LC
Java 虚拟机实现自行决定。初始化过程C
如下:
同步初始化锁,
LC
, forC
。这涉及等待直到当前线程可以获取LC
。如果
Class
对象 forC
指示C
其他线程正在进行初始化,则释放LC
并阻塞当前线程,直到通知正在进行的初始化已完成,此时重复此步骤。如果
Class
对象 forC
指示C
当前线程正在进行初始化,那么这必须是一个递归的初始化请求。释放LC
并正常完成。如果
Class
对象 forC
指示C
已经初始化,则不需要进一步的操作。释放LC
并正常完成。…
这是一个过程,对类的引用的每次解析都遵循,获取类的唯一初始化锁并在类已经初始化或当前线程是执行初始化的线程时释放它。这个锁保证了线程安全,不管这个字段是否已经声明final
,只要是在类初始化的时候写的。
它仍然是实现单例的最有效方法的原因在同一章中给出:
当可以确定类的初始化已经完成时,实现可以通过省略步骤 1 中的锁获取(并在步骤 4/5 中释放)来优化此过程,前提是,就内存模型而言,一切都发生了-在获取锁时存在的排序之前,在执行优化时仍然存在。
由于每个类只初始化一次,然后与初始化时间相比,在这个初始化状态下使用了很长时间,因此这种优化具有非常高的影响,因此,自第一个 Java 版本以来,这是最先进的。但是,正如这篇笔记所说,优化不能破坏线程安全
TA贡献1831条经验 获得超9个赞
即使我们final
从public static final Singleton instance = new Singleton ();
.
那是因为 JVM 保证在任何线程访问静态instance
变量之前创建实例。
添加回答
举报