Java 渴望单例创建线程安全吗?

我喜欢 java 中“热切单例”的简单性,大多数关于它的文章都称其创建线程是安全的。


class Singleton {


public static final Singleton instance = new Singleton ();


    private Singleton (){};


    public static Singleton getInstance(){


        return instance;


    }

}

但是,我听到一些声称它的创建毕竟可能不是线程安全的。例如,一位消息人士声称,如果使用超过 1 个类加载器或应用程序域,则是不安全的。


JVM 是否保证“Eager Singleton”的创建是线程安全的,例如,2 个线程不会意外地同时创建单例?


编辑:对象创建的线程安全是否需要关键字 final?如果该字段不是最终的,它不是线程安全的吗?


沧海一幻觉
浏览 133回答 3
3回答

缥缈止盈

您使用的方法是线程安全的。由于您没有引用您正在谈论的声明,因此我无法直接解决它们。但是 Java 语言规范对此主题很清楚。在第 17.5 节中,它描述了final字段还允许程序员在没有同步的情况下实现线程安全的不可变对象。线程安全的不可变对象被所有线程视为不可变的,即使使用数据竞争在线程之间传递对不可变对象的引用也是如此。这可以提供安全保证,防止错误或恶意代码滥用不可变类。必须正确使用 final 字段以提供不变性保证。当一个对象的构造函数完成时,它被认为是完全初始化的。只有在对象完全初始化后才能看到对对象的引用的线程可以保证看到该对象的最终字段的正确初始化值。

aluckdog

我不认为“热心单身”这个名字是合理的。考虑JLS §12.4.1.,当初始化发生时类或接口 T 将在以下任何一项第一次出现之前立即初始化:T是一个类并T创建了一个实例。由static声明的方法T被调用。一个static场宣布T分配。阿static通过声明字段T的使用量和字段不是常量变量(§4.12.4)。因此,初始化和实例化Singleton将getInstance()在第一次调用该方法时发生,或者,由于您创建了该字段public,当该字段第一次被访问时,以先到者为准。但不是更早。换句话说,这个初始化已经和所有其他尝试执行延迟初始化的尝试一样懒惰。此初始化的安全性由JLS §12.4.2, 详细初始化程序给出对于每个类或接口C,都有一个唯一的初始化锁 LC。从C到到的映射由LCJava 虚拟机实现自行决定。初始化过程C如下:同步初始化锁, LC, for C。这涉及等待直到当前线程可以获取LC。如果Class对象 forC指示C其他线程正在进行初始化,则释放LC并阻塞当前线程,直到通知正在进行的初始化已完成,此时重复此步骤。如果Class对象 forC指示C当前线程正在进行初始化,那么这必须是一个递归的初始化请求。释放LC并正常完成。如果Class对象 forC指示C已经初始化,则不需要进一步的操作。释放LC并正常完成。…这是一个过程,对类的引用的每次解析都遵循,获取类的唯一初始化锁并在类已经初始化或当前线程是执行初始化的线程时释放它。这个锁保证了线程安全,不管这个字段是否已经声明final,只要是在类初始化的时候写的。它仍然是实现单例的最有效方法的原因在同一章中给出:当可以确定类的初始化已经完成时,实现可以通过省略步骤 1 中的锁获取(并在步骤 4/5 中释放)来优化此过程,前提是,就内存模型而言,一切都发生了-在获取锁时存在的排序之前,在执行优化时仍然存在。由于每个类只初始化一次,然后与初始化时间相比,在这个初始化状态下使用了很长时间,因此这种优化具有非常高的影响,因此,自第一个 Java 版本以来,这是最先进的。但是,正如这篇笔记所说,优化不能破坏线程安全

天涯尽头无女友

即使我们final从public static final Singleton instance = new Singleton ();.那是因为 JVM 保证在任何线程访问静态instance变量之前创建实例。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java