在 Java 中,锁定是否确保对非易失性位置的读取和写入顺序正确



>假设我有一个共享的类对象:

class Shared {
    private int x = 0 ;
    private int y = 0 ;
    private Semaphore s = new Semaphore() ;
    public int readX() {
        s.p() ;
        int x0 = x ;
        s.v() ;
        return x0 ; }
    public void writeX(int x0) {
        s.p() ;
        x = x0 ;
        s.v() ; }
    public int readY() {
        s.p() ;
        int y0 = y ;
        s.v() ;
        return y0 ; }
    public void writeY(int y0) {
        s.p() ;
        y = y0 ;
        s.v() ; } }

这里的信号量是一个使用同步方法来提供互斥的类。

现在将执行以下操作:

  • 线程 0 调用 o.readX() 并发现它是 0。
  • 线程 1 使用 o.writeX(1) 将 1 写入 x,然后写入 1 到 y; o.writeY(1) ;
  • 线程 0 调用 o.readY() 得到 1,然后调用 o.readX() 。

线程 0 能否从其缓存中读取并发现 x 为 0?为什么?


编辑

这是信号量类

class Semaphore {
    private boolean available = true ;
    public synchronized void v() {
        available = true ; notifyAll() ; }
    public synchronized void p() {
        while( !available ) try{ wait() ; } catch(InterruptedException e){} 
        available = false ; }
}

根据JMM的说法,以下顺序严格按发生前关系排序,因此保证在步骤1中完成的更改对步骤4的读者的可见性:

  1. 写入 X
  2. 退出由监视器 M 保护的同步块
  3. 进入由监视器 M 保护的同步块
  4. 从 X 读取
写入变量发生 - 在释放监视器之前,释放监视器发生 - 在获取同一监视器之前

,在从变量读取之前获取监视器发生。

因此,如果 pv 同步,则线程 0 将看到更改为 x。

排显示两个线程的操作:

线程 1 线程 2o.readX();0 o.writeX(1);o.readY();1 o.writeY(1);o.readX();必须为 1
在对

任意选择的 Semaphore 方法的任何调用对进行排序之前,有一个严格的发生顺序,因为它们都在同一个共享Semaphore实例上经历一个获取-发布周期。

我们有:

  • 线程 2 o.writeX(1)发生在o.writeY(1)之前;
  • 线程 2 的o.writeY(1)发生在线程 1 o.readY() -> 1之前;
  • 线程 1 的o.readY()发生在线程 1 的第二个o.readX()之前;
  • 因此,线程 2 的o.writeX(1)发生在线程 1 的第二个o.readX()之前;
  • 因此,第二个o.readX()的结果必须是 1。

最新更新