当前位置: 首页 > 知识库问答 >
问题:

java double-check为啥要加volatile(是因为可见性还是有序性)?

冉丰茂
2023-10-26

通过百度:

  1. 我知道java volatile可以保证可见性和有序性。
  2. 我知道java单例实现:double-check模式需要加上volatile,

但是为什么需要加上volatile?百度好像有两种意见。

基于可见性的考虑,参考:https://www.bilibili.com/video/BV1gX4y1a7sH?p=11&vd_source=80...
作者的意思:没有加上volatile,不同的线程间的缓存副本无法可见,导致重复多次初始化。

基于有序性的考虑,参考:https://blog.csdn.net/qq_44842835/article/details/132166785
作者的意思:对象实例化可以简单分为三步:1、分配内存 2、初始化对象 3、将对象的引用赋值给instance。因为指令重排,顺序可以变成1->3->2,因此其他线程很可能获得一个未完全初始化的实例。

请问上述两种观点谁对谁错?能否能通过java代码来证明和实现?

共有2个答案

尉迟华翰
2023-10-26

都对,理论是基于可见性的考虑 实际上了也基于有序性的考虑, 见:
https://blog.csdn.net/java_1996/article/details/87472644
你可以试试在double-check单例模式里去掉volatile跑一下代码就可以看到问题了

乐正镜
2023-10-26

上述两种观点都有一定的正确性,但它们分别强调了volatile在解决并发问题时的不同方面。

  1. 可见性:在多线程环境中,如果一个线程的修改没有立即被其他线程看到,就可能导致数据的不一致。volatile关键字可以确保每个线程都看到共享变量的最新值。在你的例子中,如果没有volatile,不同的线程可能看不到已经初始化的对象,导致重复初始化。
  2. 有序性:在Java内存模型中,指令重排可能会导致一些意想不到的结果。例如,如果你的代码先分配内存,然后赋值给某个引用,由于指令重排,其他线程可能立即看到这个引用指向未初始化的内存地址。通过使用volatile,可以确保分配内存、初始化对象和设置引用的顺序不会被重排,从而防止其他线程看到未完全初始化的对象。

下面是一个简单的Java代码示例,用于证明volatile关键字对double-check单例模式的重要性:

public class Singleton {    private static volatile Singleton instance;    private Singleton() {}    public static Singleton getInstance() {        if (instance == null) {            synchronized (Singleton.class) {                if (instance == null) {                    instance = new Singleton();                }            }        }        return instance;    }}

在这个例子中,如果没有volatile关键字,两个线程可能会同时进入if (instance == null)的判断逻辑分支,并同时创建新的Singleton实例。使用volatile关键字可以确保只有一个线程能够进入同步块,并成功创建单例实例。

这个例子也说明了volatile关键字对于保证单例模式的有序性和可见性都是非常重要的。

 类似资料:
  • 本文向大家介绍一个参数既可以是const还可以是volatile吗?解释为什么。相关面试题,主要包含被问及一个参数既可以是const还可以是volatile吗?解释为什么。时的应答技巧和注意事项,需要的朋友参考一下 • 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。  

  • 我正在尝试在 Kotlin 中生成一个单例,并且遇到了问题,因为我无法。 这似乎是制作单例的一种非常标准的方法。为什么它不让我,我该如何解决它?

  • 编辑:更正了下面ARLCode注意到的CSS中的一个错别字-不相关。只使用CSS,我尝试动画一些文本,这样不同的文本块开始隐藏,在计时器上变得可见,然后在计时器上淡出,按顺序。 首先,我从使用隐藏的所有文本开始,并添加一个动画以在n秒后更改可见性值。 此外,我在 中嵌套了 并添加了一个动画,通过动画化不透明度来淡化 。这将在(n+x)秒后淡出刚刚出现的文本。 淡出没有问题,但弹出从来不起作用。当我

  • 本文向大家介绍请问GC是什么? 还有为什么要有GC?相关面试题,主要包含被问及请问GC是什么? 还有为什么要有GC?时的应答技巧和注意事项,需要的朋友参考一下 考察点:回收 GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存

  • 找不到init? 那起的函数名有什么用?

  • 问题内容: 我正在尝试设置禁用输入的样式。我可以用: 要么 属性选择器是现代CSS3方式还是前进的方式?我曾经使用伪类,但是找不到关于它们是否是旧方法并且将不被支持或者它们是否相等的任何信息,您可以使用最喜欢的任何方法。 我不需要支持较旧的浏览器(这是一个Intranet应用程序),因此: 属性是更新更好的 伪类仍然是要走的路 无论您最喜欢哪个 有一个技术上的理由要使用另一个 问题答案: 属性选择