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

普通成员(非易失性成员)仍然具有易失性读写的内存语义

穆睿才
2023-03-14

当我在jdk1.8中阅读AbstractQueuedSynChronizer时,我看到compareAndSetState方法具有易失性读写的内存语义学的注释。

注释和代码如下:

/**
 * Atomically sets synchronization state to the given updated
 * value if the current state value equals the expected value.
 * This operation has memory semantics of a {@code volatile} read
 * and write.
 */
protected final boolean compareAndSetState(int expect, int update) {
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

在AbstractQueuedSynchronizer类中,stateOffset是一个名为state

只是想知道如果state是一个非易失性成员,记忆语义学是什么。

共有1个答案

叶稳
2023-03-14

compareAndSetState()的语义学仍然是易失性读写-这是Unsafe.compareAndSwapInt()存在的主要原因。

但是通常代码不仅仅调用Unsafe.compareAndSwapInt()。通常代码读取当前值,计算一个新值,然后尝试用新值替换它读取的值。这种读取也必须使用易失性读语义学来完成。

例如,在CountDownLatch中。同步#tryReleaseShared()

   protected boolean tryReleaseShared(int releases) {
       // Decrement count; signal when transition to zero
       for (;;) {
           int c = getState();
           if (c == 0)
               return false;
           int nextc = c-1;
           if (compareAndSetState(c, nextc))
               return nextc == 0;
       }
   }

使用getState()读取状态必须使用volatile读取语义,以确保使用最新的值

 类似资料:
  • 在阅读了这个问题和这个(尤其是第二个答案)之后,我对volatile及其关于记忆障碍的语义感到非常困惑。 在上面的例子中,我们写入一个易失性变量,这会导致一个mitch,这反过来会将所有挂起的存储缓冲区/加载缓冲区刷新到主缓存,使其他缓存行无效。 然而,非易失性字段可以优化并存储在寄存器中,例如?那么,我们如何才能确保给定一个写入易失性变量之前的所有状态变化都是可见的呢?如果我们有1000件东西呢

  • 我对下面的代码段有一个问题。结果可能有一个结果[0,1,0](这是用JCStress执行的测试)。那么这是怎么发生的呢?我认为数据写入(data=1)应该在Actor2(guard2=1)中写入到guard2之前执行。我说得对吗?我问,因为很多时候我读到挥发物周围的说明没有重新排序。此外,根据这一点:http://tutorials.jenkov.com/java-concurrency/vola

  • 问题内容: 我尝试了解为什么此示例是正确同步的程序: 由于存在冲突的访问(存在对a的写入和读取),因此在每个顺序一致性中,必须在访问之间的关系之前执行。假设顺序执行之一: 是1发生-在2之前发生,为什么? 问题答案: 不,在相同变量的易失性写入之前(以同步顺序),在易失性写入 之前 不一定 会发生 易失性读取。 这意味着它们可能处于“数据争用”中,因为它们“冲突的访问未按先发生后关系进行排序”。如

  • 问题内容: 观察以下用Java编写的程序(紧随其后的是完整的可运行版本,但是该程序的重​​要部分在下面的摘录中): 说明 :该程序实际上非常简单。它加载整数和从系统属性(传递给JVM与标志) -这些是输入长度和螺纹以后使用的数量。然后,它解析第一个命令行参数,该参数说明重复程序多少时间(我们要确保JIT已完成工作并具有更可靠的度量)。 每次重复调用该方法。该方法只是启动线程,每个线程都将进行迭代循

  • 我正在使用一个API,该API为内存映射的I/O提供指针。它通过填写指针到指针的参数来实现这一点: 因为这是内存映射的I/O,所以我很确定我应该在这里使用。(我不知道为什么他们没有将参数设为。) 但是,我的volatile void**不能隐式转换为函数的,因此我不能直接传入它: 我目前正在使用一个额外的变量和一个单独的赋值步骤来解决这个问题: 这似乎很冗长。在这种情况下,当指针传入时,将vola

  • 如果是,如果被添加到数组中,强制转换会受到什么影响?谢谢你! 编辑:@cacahuete Frito链接了一个非常相似的问题:带有'volatile'数组的'memcpy((void*)dest,src,n)'安全吗?