问题标签 [happens-before]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
85 浏览

java - 易失性和非易失性字段混合时发生易失性关系

当易失性和非易失性字段混合时,我试图了解易失性字段的发生前行为。

假设有 1 个 WriteThread 和 5 个 ReadThreads,它们更新/读取 SharedObject。

ReadThreads 从头开始​​调用方法,WriteThread在 1 秒后waitToBeStopped()调用该方法。stop()

当这个程序结束时,输出是这样的。即使我尝试了 100 多个 ReadThreads,结果也总是一样的。

Q1。有人可以解释为什么这总是返回 4,5,6,7,8,9 而不是 1,2,3,0,0,0?

我对happens-before关系的理解是这样的:

  • WriteThread 写入a=1,b=2,c=3 发生在WriteThread 写入之前stopRequested
  • WriteThread 写入stopRequested 发生在WriteThread 写入之前a=4,b=5,c=6,d=7,e=8,f=9
  • WriteThread 写入stopRequested 发生在ReadThread 读取之前stopRequested
  • ReadThread 读取stopRequested 发生在ReadThread 读取之前a,b,c,d,e,f

从这 4 个陈述中,我无法得出这样的陈述……

  • WriteThread 写入a=4,b=5,c=6,d=7,e=8,f=9 发生在ReadThread 读取之前a,b,c,d,e,f

如果有帮助,这是代码的另一部分:

0 投票
2 回答
54 浏览

java - 我们可以将 Java 中的最终重新排序规则视为发生在规则之前吗?

Java中存在两条最终记录规则,如下:

  1. a write to final field in constructor并且the constructed instance reference is assigned to variable afterwards不能重新排序
  2. read a instance reference并且read the final field in the instance afterwards不能重新排序

我们可以将上述规则视为发生之前的规则吗?

  1. a write to final field in constructor发生之前the constructed instance reference is assigned to variable afterwards
  2. read a instance reference发生之前read the final field in the instance afterwards

我认为发生在规则之前的语义更强。

0 投票
2 回答
63 浏览

java - 不稳定的 Java 重新排序

首先让我说,我知道这是一个相当普遍的话题,但在搜索它时,我找不到另一个可以澄清以下情况的问题。如果这可能是重复的,我很抱歉,但是你去:

我是并发新手,为了回答问题,我得到了以下代码:

  • a)为什么除了“00”之外的任何其他输出都是可能的?
  • b) 如何修改代码以便始终打印“00”。

对于a ) 我的回答如下:在没有任何 volatile / 同步构造的情况下,编译器可以重新排序一些指令。特别是“this.initialInt = val;” 和“this.flag = true;” 可以切换,以便发生这种情况:线程都已启动并且 t1 提前收费。给定重新排序的指令,它首先设置 flag = true。现在在它到达“this.initialInt = val;”的最后一条语句之前 另一个线程跳进来,检查 if 条件并立即返回,从而打印未更改的 initialInt 值 1。除此之外,我相信如果没有任何 volatile / 同步,不确定 t2 是否会看到在 t1 中对 initialInt 执行的分配所以它也可以打印“1”作为默认值。

对于b)我认为该标志可能会变得不稳定。我了解到,当 t1 写入 volatile 变量设置 flag = true 然后 t2 时,在 if 语句中读取此 volatile 变量时,将看到在 volatile 写入之前执行的任何写操作,因此 initialInt = val 也是。因此,t2 已经看到它的 initialInt 值更改为 0,并且必须始终打印 0。但是,如果使用 volatile 成功阻止了我在 a) 中描述的任何重新排序,这只会起作用。我已经阅读过有关 volatile 完成此类事情的信息,但我不确定在没有任何进一步同步块或任何此类锁的情况下这是否总是有效。从这个答案我已经收集到,在 volatile 存储(因此 this.flag = true)可以重新排序以使其超出它之前没有发生任何事情。在那种情况下,initialInt = val 不能向下移动,我应该是正确的,对吧?或不 ?:)

非常感谢你的帮助。我期待着您的回复。

0 投票
2 回答
151 浏览

multithreading - Java volatile 读取可见性保证

我在阅读 JVM 在读取 volatile 变量时提供的可见性保证时遇到了以下摘录: “当线程 A 写入 volatile 变量并且随后线程 B 读取相同的变量时,A 之前可见的所有变量的值在读取 volatile 变量后,写入 volatile 变量对 B 可见。”

我对 JVM 的这个保证有疑问。考虑以下一组类:

想象一下 2 个线程 Th1 和 Th2 在不同的 CPU 中运行,它们的指令执行顺序由每行中的注释指示(在它们的运行方法中)。我的问题是:当代码“int x = p2.c;”时 在 t = 6 时执行,线程 Th2 可见的变量应根据上述段落从主存储器刷新。据我了解,此时主存储器将拥有来自 Th1 的所有写入。变量 p2.b 在 t = 7 打印时会显示什么值?

  • p2.b 的值是否会显示为 10,因为它的值是从 volatile 变量 p2.c 的读取中刷新的?
  • 或者它会以某种方式保留值 30?
0 投票
2 回答
72 浏览

java - 为什么'发生在之前; 关系叫这样吗?

我理解这个概念的所有内容,除了为什么这样称呼它。有人可以帮我理解吗?它仍然让我感到困惑..这是我唯一的问题。我读了几篇文章,我仍然无法弄清楚它的名字的动机。

0 投票
2 回答
372 浏览

java - HashMap vs ConcurrentHashMap:线程间传输

我有一个关于在多线程应用程序中使用地图的问题。假设我们有这样的场景:

  1. 线程接收List<Map<String, Object>>由 Jackson Json 反序列化的 json 数据。
  2. 该线程修改接收到的地图。
  3. 然后将列表放入阻塞队列以供另一个线程使用。

如您所见, map 仅由单个线程修改,但随后它“变为”只读(没有变化,只是不再修改)并传递给另一个线程。接下来,当我研究HasMap(also TreeMap) 和ConcurrentHashMap的实现时,后者有volatile字段,而前两个没有。那么,在这种情况下我应该使用哪个实现MapConcurrentHashMap是矫枉过正的选择还是由于线程间传输而必须使用?

我的简单测试表明,HashMap/TreeMap当它们被同步修改并且有效时我可以使用,但是我的结论或我的测试代码可能是错误的:

主线程产生 5 个同步更新公共地图的子线程,当它们完成主线程成功看到子线程的所有更新时。

0 投票
1 回答
123 浏览

java - Java 发生之前的关系 invokeAndWait

我的问题与这个问题有关,它已经有了答案:

是的,在线程调用/的操作和由此提交的可运行的 EDT 上的操作之间存在发生之前的关系。invokeLaterinvokeAndWait

我的问题有点笼统:是否甚至可以实现一个方法,invokeAndWait例如 ,使其正常工作,但不强加发生前的关系?通过正常工作的方法,我的意思是:

  • 提交Runnable的保证只执行一次。
  • 提交Runnable在特定线程上执行。
  • 该方法一直等到提交的执行Runnable完成。
  • 该方法保证在提交的执行Runnable完成后返回。

对我来说,如果不强加发生之前的关系,似乎没有办法实现这一点,还是我错了?如果是这样,请包含一个示例实现,以证明这一点。

0 投票
1 回答
59 浏览

java - JVM 是否会使用 Happens-Before 更新所有线程的字段值,而不直接为字段赋值?

我已经知道,如果我从另一个线程写入非易失性字段,他可能会缓存它,这样所有其他线程都不会看到实际值。但是,如果我在线程对象上调用例如start()AFTER 分配值到归档,JVM 将为所有其他线程更新这个值。但是,如果我将执行相同的操作但不直接将值分配给字段,JVM 会更新该字段的值,如下所示:object.field = 100但使用调用方法object.setFiled(100)

在这种情况下,所有其他线程的字段值肯定是相同的

但是在这种情况下结果会一样吗?

0 投票
1 回答
88 浏览

java - 与 ConcurrentSkipListSet 一起正常工作的动态比较器

我正在尝试使用

queue = new ConcurrentSkipListSet<Task>(Comparators.comparing(Task::priority))

作为具有唯一元素的并发优先级队列(请参阅此处的类似讨论),但我需要不时更改任务的优先级。

显然,改变元素在集合中的优先级就像打开一罐蠕虫;幸运的是,我只需要在将它们从queue中删除之后以及重新提交它们之前更改它们的优先级。更准确地说,我用来pollFirst()从 中弹出一个元素queue,我可能需要在更新其优先级(具有较低优先级)后重新提交。

如果这是一个串行实现,那么在元素位于集合之外时更改元素的优先级应该没有问题。

使用并发访问进行此更新的线程安全方式是什么? 是否足以保证

task = queue.pollFirst()以前发生过task.priorityUpdate(),以前发生过queue.add(task)

0 投票
2 回答
105 浏览

java - Java 中的不安全发布

在Brian Goetz 等人的《 Java Concurrency in Practice 》一书中:

如果您不能确保在另一个线程加载该共享引用之前发布共享引用,那么可以通过写入其字段来重新排序对新对象的引用的写入(从使用该对象的线程的角度来看)。在这种情况下,另一个线程可以看到对象引用的最新值,但该对象的部分或全部状态(部分构造的对象)的值已过期。

这是否意味着:在发布对象的线程中,对新对象的引用的写入不会随着对其字段的写入而重新排序;对其字段的写入发生在引用的写入之前。但是,该发布线程可能会在刷新更新的对象字段之前刷新对主内存的更新引用。因此,使用对象的线程可能会看到对象的非空引用,但会看到对象字段的过时值?从这个意义上说,操作是为消费线程重新排序的。