当前位置: 首页 > 面试题库 >

重新排列读取

晏沈义
2023-03-14
问题内容

假设有两个没有同步的线程,一个设置n = 1另一个执行method()

在下文中,“读取”始终指字段的读取n

public class MyClass
{
  public int n = 0;

  public void method() {
    System.out.println(n); //read 1
    System.out.println(n); //read 2
  }
}

以下输出可能吗?

1
0

答案是肯定的,因为即使读1发生在读2之前,但是由于读2不会改变线程内执行的语义,因此仍可能在读1之前对读2重新排序。

这个推理正确吗?


问题答案:

发生在前并不意味着两个任意操作的顺序。更精确地说,出现这种情况,之前所做的最重要的事情是占用 的写入读取之前发生的一致性
。值得注意的是,它告诉读者可以进行哪些写操作:最后一次写入按发生在先的顺序发生,或者任何其他未按发生在发生在先的顺序进行的写入(种族)。请注意,在不违反该要求的情况下,两次连续读取可能会看到从不同的(读写)写入获得的不同值。

例如JLS 17.4.5说:

应该注意的是,两个动作之间存在先发生关系并不一定意味着在实现中它们必须按照该顺序进行。如果重新排序产生的结果与合法执行相符,则不合法。

这样的数据争夺是令人毛骨悚然的:读写读取会在每次读取时返回令人惊讶的数据,而Java内存模型会捕获这些数据。因此,更精确的答案是产生(1,0)的执行不会违反Java内存模型约束(同步顺序一致性,同步顺序-
程序顺序一致性,先发生的一致性,因果关系要求),因此是允许的。

实施方面:在硬件上,由于它们是独立的,因此无论它们的“程序顺序”如何,这两种负载都可以在不同的时间启动和/或到达内存子系统。在编译器中,指令调度也可以不考虑程序顺序来进行独立读取,从而以“反直观”的顺序将负载暴露给硬件。

如果希望按程序顺序进行 读取
,则需要更强的属性。JMM将属性赋予同步操作(在您的示例中,创建一个变量volatile将使该操作生效),该属性将这些操作按与程序顺序 一致
同步顺序进行 绑定 。在这种情况下,将禁止(1,0)。

一个非常特殊的jcstress测试用例的插图(请参见警告的完整资料):

private final Holder h1 = new Holder();
private final Holder h2 = h1;

private static class Holder {
    int a;
    int trap;
}

@Actor
public void actor1() {
    h1.a = 1;
}

@Actor
public void actor2(IntResult2 r) {
    Holder h1 = this.h1;
    Holder h2 = this.h2;
    h1.trap = 0;
    h2.trap = 0;
    r.r1 = h1.a;
    r.r2 = h2.a;
}

即使在不重新排序负载的x86上,也会产生(1、0),哎呀:

      [OK] o.o.j.t.volatiles.ReadAfterReadTest                                                                                                      
    (fork: #1, iteration #1, JVM args: [-server])
  Observed state   Occurrences              Expectation  Interpretation                                              
          [0, 0]    16,736,450               ACCEPTABLE  Doing both reads early.                                     
          [1, 1]   108,816,262               ACCEPTABLE  Doing both reads late.                                      
          [0, 1]         3,941               ACCEPTABLE  Doing first read early, not surprising.                     
          [1, 0]        84,477   ACCEPTABLE_INTERESTING  First read seen racy value early, and the s...

使为Holder.avolatile将使(1、0)消失。



 类似资料:
  • 问题内容: 我需要移动现有列的位置(以获得更好的可见性)。 如何做到这一点而又不影响数据? 问题答案: 修改也可以。看一看:

  • 问题内容: 我有一个4d numpy数组,该数组代表具有3d实例的数据集。可以说数组的形状是。 如何将数组的形状更改为? -–问题更新似乎rollaxis和transpose都能解决问题。 感谢您的回复! 问题答案: 该函数完全可以实现您想要的功能,您可以传递轴参数来控制要交换的轴: b的轴是a的轴的置换版本:b的轴0是a的第3轴,b的轴1是a的第0轴,依此类推… 这样,您可以在第二或第三位指定要

  • 我是Python的业余爱好者,我制作了一个程序,可以对长字符串进行编码并输出6个字符。 标记将数字(n)转换为字符。大写和小写字母,包括“-”和“”字符。 这是编码的其余部分。 同样,是否有方法为输出的六个字符创建顺序? 这是我到目前为止所拥有的。我从一个现有的问题中得到了这个。 如何在python中重新排序列表? 但是...它给了我这个: 我想发生的事: 我对这个完全陌生。请帮助:)

  • 问题内容: 如果我有列表,如何以任意方式重新排序商品? 编辑:我不想洗牌。我想以预定义的方式对它们进行重新排序。(例如,我知道旧列表中的第3个元素应成为新列表中的第一个元素) 问题答案: 你可以这样

  • 问题内容: 我在python / pyspark中有一个带有列的数据框 ,依此类推...... 现在,我在此数据框中添加了新列。 现在,我必须安排这样的列的列来后 我已经完成如下 我收到此错误 为什么会发生此错误。我该如何纠正。 问题答案: 您可以用来更改列的顺序:

  • 问题内容: 有没有办法将numpy 2D数组中的列顺序更改为新的任意顺序?例如,我有一个数组 我想将其更改为 通过应用排列 在列上。因此,在新矩阵中,我希望将原始文档的第一列保留在原位置,将第二列移至最后一列,依此类推。 有一个numpy函数可以做到吗?我有一个相当大的矩阵,并且希望得到更大的矩阵,因此我需要一个可以在可能的情况下快速且适当地执行此操作的解决方案(置换矩阵是不可行的) 谢谢。 问题