1

Here's the problem I'm facing. On running the below code, I'm sometimes getting stale data when printing the content of B. I can't really understand why this is happening since updating and receiving the contents of B are protected by B's lock.

Notice that the during update to B, both the locks of A and B are held. While accessing the contents of B, only a single lock is held.

Also Notice that B.updated() is not synchronized, but I don't think this is the problem since I'm making sure that the updated counter is set to 2, before I access the content of B.

class B {
  Object data
  int updated = 0

  // get and set protected by B's monitor
  synchronized Object getData() {
    return data;
  }
  synchronized setData(Object d) {
    data = d;
    updated += 1;
  }
  // deliberately not synchronized
  int updated() { return updated; }
}

class A {
    B b
    A() {
        new Thread t = new Thread(new UpdaterThread());
        t.start();
    }

   // when B is updated both A and B monitors are held
    synchronized String setB(Object data) {
      b.setData(data);
   }

   class UpdateThread implements Runnable {
     public void run() {
       // updating B to new Value
       setB("B2");
     }
   }
}

public static void main(String[] _) {
   B b = new B();  
   b.setData("B1");
   A a = new A();
   while (b.updated() == 1) {
     // wait for updated to reach 2
   } 
   println(b.getData());  // prints "B1" sometimes, but very rarely.
}
RD.
  • 300
  • 4
  • 12

1 Answers1

5

You are expecting the code to be sequentially consistent. However, Java guarantees sequential consistency only, if there are no data races in the code.

Also Notice that B.updated() is not synchronized, but I don't think this is the problem since I'm making sure that the updated counter is set to 2, before I access the content of B.

That's the problem. You have a data race on the variable updated, because one thread writes to it, and another threads reads from it without any synchronization.

If you make the variable volatile, the code will work, because there are no data races on volatile variables.

nosid
  • 48,932
  • 13
  • 112
  • 139
  • I don't think making the variable volatile is sufficient. The volatile keyword will flush the value to main memory for visibility in other threads; however, I don't think it guarantees synchronization with updates to other variables. The value of 'updated' can still get flushed first, with the result that the main() method can still see `b` updated when the value of `data` has not yet been flushed and is not yet visible. – Warren Dew Jun 29 '14 at 07:24
  • 1
    @WarrenDew: http://stackoverflow.com/questions/13688697/is-a-write-to-a-volatile-a-memory-barrier-in-java – nosid Jun 29 '14 at 07:47