Reputation: 41
Can someone explain where the race condition is in this piece of code. My lecturer set it and I don't fully understand how to spot them yet, or say why the result that is given happens.
public class SlowRace {
public static void main(String args []) throws Exception {
MyThread.count = 0 ;
MyThread thread1 = new MyThread() ;
thread1.name = "A" ;
MyThread thread2 = new MyThread() ;
thread2.name = "B" ;
thread1.start() ;
thread2.start() ;
thread2.join() ;
thread1.join() ;
System.out.println("MyThread.count = " + MyThread.count) ;
}
}
class MyThread extends Thread {
volatile static int count ;
String name ;
public void run() {
for(int i = 0 ; i < 10 ; i++) {
delay() ;
int x = count ;
System.out.println("Thread " + name + " read " + x) ;
delay() ;
count = x + 1;
System.out.println("Thread " + name + " wrote " + (x + 1)) ;
}
}
static void delay() {
int delay = (int) (1000000000 * Math.random()) ;
for(int i = 0 ; i < delay ; i++) {}
}
}
The result that gets returned:
Thread A read 0
Thread A wrote 1
Thread B read 0
Thread A read 1
Thread B wrote 1
Thread A wrote 2
Thread B read 2
Thread A read 2
Thread B wrote 3
Thread A wrote 3
Thread B read 3
Thread A read 3
Thread B wrote 4
Thread A wrote 4
Thread B read 4
Thread A read 4
Thread B wrote 5
Thread A wrote 5
Thread B read 5
Thread A read 5
Thread B wrote 6
Thread A wrote 6
Thread B read 6
Thread A read 6
Thread B wrote 7
Thread A wrote 7
Thread B read 7
Thread A read 7
Thread B wrote 8
Thread A wrote 8
Thread B read 8
Thread A read 8
Thread B wrote 9
Thread A wrote 9
Thread B read 9
Thread A read 9
Thread B wrote 10
Thread A wrote 10
Thread B read 10
Thread B wrote 11
MyThread.count = 11
Upvotes: 1
Views: 113
Reputation: 298
This logic is thread-unsafe because of unprotected update to static variable count in the class MyThread.
Main thread will join Thread1 and Thread2, after starting them and will await their completion. However, simultaneously running threads(Thread1,Thread2) with unlucky timing can end up updating variable "count" together with same value.
Upvotes: 0
Reputation: 116908
Hey guys could someone explain where the race condition is in this piece of code,
The race is between these lines:
int x = count ;
...
count = x + 1;
One thread gets the value but another thread could get the same value before the first thread updates it with the incremented value. That's the race.
count
and stores it in x
. x
is (let's say 10).count
and stores it in x
. x
is (let's say 10).x
to be 11
and stores it back to count
.x
to be 11
and stores it back to count
-- this overwrites the thread-1's increment.So instead of count
being 12, one of the increments will have been lost and it will be 11.
The exercise is to point out that increment is not atomic. Really the delay()
is not necessary. count++
would have demonstrated the problem as well since it is not atomic (get/increment/set) and the thread can be interrupted in the middle of the 3 operations.
One thing that complicates this code is that System.out.println(...)
is synchronous so the console output will change the timing of the program.
Upvotes: 2
Reputation: 9038
You are telling the compiler to store the information on memory instead of cache.
volatile static int count ;
2 threads executing this run in the same time.
public void run() {
for(int i = 0 ; i < 10 ; i++) {
delay() ;
int x = count ;
System.out.println("Thread " + name + " read " + x) ;
delay() ;
count = x + 1;
System.out.println("Thread " + name + " wrote " + (x + 1)) ;
}
}
Imagine.
count = 0;
Thread1(int x = count); //x = 0;
Thread1(delay)
Thread2(int x = count); //x = 0;
Thread2(delay)
Thread1(count = x + 1); //count = 1;
Thread2(count = x + 1); //count = 1; //While it has to be 2.
Upvotes: 0