Theodore Norvell
Theodore Norvell

Reputation: 16231

In Java, does locking ensure correct order of reads and write to nonvolatile locations

Suppose I have a shared object of class:

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() ; } }

Here Semaphore is a class that uses synchronized methods to provide mutual exclusion.

Now the following actions happen:

Could thread 0 read from its cache and find that x is 0? Why?


EDIT

Here is the Semaphore class

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 ; }
}

Upvotes: 1

Views: 106

Answers (2)

Marko Topolnik
Marko Topolnik

Reputation: 200166

Presenting the actions of your two threads side-by-side:

Thread 1                       Thread 2
o.readX(); // 0                o.writeX(1);
o.readY(); // 1                o.writeY(1);
o.readX(); // must be 1

There is a strict happens-before ordering of any arbitrarily chosen pair of invocations of your Semaphore methods because they both go through an acquire-release cycle on the same shared Semaphore instance.

We have:

  • o.writeX(1) by Thread 2 happens-before o.writeY(1);
  • o.writeY(1) by Thread 2 happens-before o.readY() -> 1 by Thread 1;
  • o.readY() by Thread 1 happens-before the second o.readX() by Thread 1;
  • therefore o.writeX(1) by Thread 2 happens-before the second o.readX() by Thread 1;
  • therefore the result of the second o.readX() must be 1.

Upvotes: 3

According to JMM the following sequence is strictly ordered by happens-before relationship and therefore guarantees visibility of change done in the step 1 to reader at step 4:

  1. write to x
  2. exit from synchronized block guarded by monitor M
  3. entering into the synchronized block guarded by monitor M
  4. read from x

Write to variable happens-before releasing the monitor, releasing the monitor happens-before acquiring the same monitor and acquiring the monitor happens-before read from variable.

So if p and v are synchronized then thread 0 will see the change to x.

Upvotes: 3

Related Questions