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

字段读取同步和volatile之间的可见性差异

董品
2023-03-14

我读了SO的以下文章

字段读取同步和易失性之间的区别

发问者写道

同步的目的是确保此线程读取的acct.balance值是当前值,并且对acct.balance中对象字段的任何挂起写入也会写入主存。

最受欢迎的答案:

你是正确的。

请研究此代码:

public class VolatileTest {

    static/* volatile */boolean done = false;

    public VolatileTest() {
        synchronized (this) {

        }

    }

    public static void main(String[] args) throws Exception {
        Runnable waiter = new Runnable() {
            public void run() {
                while (!done)
                    ;
                System.out.println("Exited loop");

            }
        };
        new Thread(waiter).start();
        Thread.sleep(100); // wait for JIT compilation
        synchronized (VolatileTest.class) {
            done = true;
        }
        System.out.println("done is true ");
    }

}

在我的电脑上,这个程序不会终止。

因此我认为

  1. 如果我更改volatile变量,我将在另一个线程中看到任何未完成的地方的实际值

我说得对吗?

共有2个答案

安明亮
2023-03-14

你是对的)

这里描述了内存模型:Java内存模型

它特别指出:

监视器上的解锁发生在该监视器上的每个后续锁定之前。

以及

对易失性字段(§8.3.1.4)的写入发生在该字段的每次后续读取之前。

因此,只有在同一个监视器上的锁定和解锁才会按照您想要的方式进行,并且对易失性变量的所有写入和读取也是如此。因此,您的程序可能不会终止,因为您在没有锁定所述监视器的情况下读取并且没有发生之前的关系。

有一点需要注意(这就是多线程bug如此恼人的原因):
您可能会在其他线程中看到变化。也可能不会。在大多数架构上,您可能会在正常处理过程中看到它,并且可能会在高负载过程中出现错误,使其难以复制。JVM不保证如果之前没有发生任何事情(即volatile、synchronized、在同一线程中或在链接中的其他情况下),JVM将在何时看到它,但会尽最大努力平稳运行。

邴英毅
2023-03-14
  1. 是的,这是正确的,因为易失性写入发生在从变量读取写入值之前
  2. 不完全是这样。可以保证同一监视器上的另一个同步线程将看到更新的值,因为监视器释放发生在另一个线程获取同一监视器之前。如果不获取相同的监视器,其他线程可能会看到更新的值。你公式中的“唯一”太强了:)
 类似资料:
  • 问题内容: 我想简化我的jQuery Backbone.js Web应用程序中的内容。一种简化就是我的菜单和对话框小部件的行为。 以前,我是在开始时创建菜单的div框并使用来隐藏它们的。当我需要菜单时,我更改了样式,然后使用jQuery ui位置工具定位div框(由于无法定位具有的元素),完成后,最终将其样式更改为。 现在,我想用隐藏它们,然后在需要时使用position实用工具,然后将样式更改为

  • 本文向大家介绍同步和异步时序电路之间的差异,包括了同步和异步时序电路之间的差异的使用技巧和注意事项,需要的朋友参考一下 顾名思义,同步时序电路和异步时序电路都是将反馈用于下一代输出的时序电路的类型,但是根据这种反馈的类型,可以区分两个电路。 以下是同步和异步时序电路之间的重要区别 - 序号 键 同步时序电路 异步时序电路 定义 另一方面,异步时序电路是数字时序电路,其中到下一个生成的输入的反馈不受

  • 问题内容: 我读过有关将对象标记为volatile的方法,不能保证其成员的可见性( 我不是在说线程安全,而只是在内存可见性 ,引用: JVM仅将对象引用视为易失性,而不会将驻留在堆上的对象数据本身视为易失性 我的问题: 如果成员已被编辑,则同步将确保成员(在同一锁定对象上)的可见性。那是因为 发生在锁的末尾(释放)之前, 这使得操作对其他线程可见? 在对象上使用易失性的情况下,对象引用也会更改。如

  • 我们使用意图在两个活动之间切换,片段也是出于相同的目的。那么为什么我们不能总是使用意图而不是片段呢?

  • 我不熟悉随机文件访问,我遇到了一个问题——据我所知,RandomAccessFile类提供了一个用于读/写的随机访问文件。我可以使用seek()方法移动到首选位置并开始阅读或写作,但在这种情况下并不重要。完全是随机访问吗?但在FileInputStream中,我有同样的能力 这种方法提供了我从某个特定的地方阅读。那么,有什么区别呢?(我猜,输入流读取所有文件,但只是通过断路位置之前的所有符号,但它

  • 问题内容: 我很好奇是否有人在使用私有字段而不是公共获取方法注释实体之间的性能差异方面有任何困难的数字。我听说人们说字段变慢了,因为它们被称为“通过反射”,但是getter方法也是,不是吗?Hibernate需要它试图读它,我可以看到有一些前场的无障碍设置为true 轻微的 开销。但是,这不是在Session范围内的类级别上完成,还是在读取Configuration并构建SessionFactor