rob1994
rob1994

Reputation: 41

Finding the race condition

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

Answers (3)

drop.in.ocean
drop.in.ocean

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

Gray
Gray

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.

  1. thread-1 gets the value of count and stores it in x. x is (let's say 10).
  2. At the same time, thread-2 also gets the value of count and stores it in x. x is (let's say 10).
  3. thread-1 increments x to be 11 and stores it back to count.
  4. thread-2 increments its copy of 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

RamonBoza
RamonBoza

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

Related Questions