Domanda

I was told that the following code example has a data race condition (assuming multiple threads, of course):

class C { 
 private int x = 0; 
 private int y = 0; 

 void f() { 
     x = 1; 
     y = 1; 
 } 

 void g() { 
     int a = y; 
     int b = x; 
     assert(b >= a); 
 } 
} 

Yet, I am told that the following "fix" does not have data races:

class C { 
 private int x = 0; 
 private int y = 0; 

 void f() { 
     synchronized(this) { x = 1; } 
     synchronized(this) { y = 1; } 
 } 

 void g() { 
     int a, b; 
     synchronized(this) { a = y; } 
     synchronized(this) { b = x; } 
     assert(b >= a); 
 } 
}

Understandably, there are other problems with the above examples, but I just want to know why the second code block has no race conditions. How does synchronizing each assignment statement eliminate the data race condition? What is the significance of synchronizing only a single assignment statement at a time?

Just to clarify, data race is defined as such:

Data races: Simultaneous read/write or write/write of the same memory location

È stato utile?

Soluzione

In the first example the data race condition will be noticed by having the assert fail.

So how is this possible? y > x should always be false, as y is written after x and read before x.

Even if you consider all interleaving of

            Thread 1                 Thread 2
            ----------------------------------
            read y
            read x
                                     write x 1
                                     write y 1

you should always have x <= y

But in a safe execution, if read v during the execution of a write v, there is no guarantee on the value read.

v is 0
T1 write 1:   wwwwwwwww
T2 read   :         rrrrr 
T3 read   :               rrrrr

In this case the value read by T2 can be anything, like 42. Meanwhile, the value read by T3 is guaranteed to be 1.

In the first case a and b can be anything, so the assertion may fail. The "fix" offers the guarantee that the data race (concurrent read\write) will never occur, and that a and b will always be either 0 or 1.

Altri suggerimenti

Whoever told you this was wrong; the race condition (changing x and y before the assert; actually, just assert (x >= y); has the same problem) is still present if you synchronize separately.

A JIT JVM might very well perform lock coarsening and move both pairs of assignments into a single synchronized block, but that's not guaranteed by the language semantics.

The synchronized keyword is all about different threads reading and writing to the same variables, objects and resources. This is not a trivial topic in Java, but here is a quote from Sun:

Synchronized methods enable a simple strategy for preventing thread interference and memory consistency errors: if an object is visible to more than one thread, all reads or writes to that object's variables are done through synchronized methods.

In a very, very small nutshell: When you have two threads that are reading and writing to the same 'resource', say a variable named foo, you need to ensure that these threads access the variable in an atomic way. Without the synchronized keyword, your thread 1 may not see the change thread 2 made to foo, or worse, it may only be half changed. This would not be what you logically expect.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top