2

I just wanted to write an example for an race condition:

MyParallelClass.java:

public class MyParallelClass implements java.lang.Runnable {
    public int counter = 0;

    @Override
    public void run() {
        if (test.globalVar > 0) {
            for (int i = 0; i < 1000000; i++) {
                counter++;
            }
            test.globalVar--;
        }
    }
}   

test.java:

public class test {
    public static int globalVar;

    public static void main(String[] args) {
        globalVar = 1;

        MyParallelClass a = new MyParallelClass();
        MyParallelClass b = new MyParallelClass();

        new Thread(a).start(); // Thread A
        new Thread(b).start(); // Thread B

        System.out.println(globalVar);
    }
}   

What I thought would happen:

I thought this could output either 0 if thread A was executed completely before Thread B starts.

The variable test.globalVar could also get manipulated like this:

Thread A                     -  Thread B  
checks if (globalVar > 0)
      looping ...               checks if (globalVar > 0)
      looping ...               execute all four bytecode commands of "test.globalVar--;"
      execute test.globalVar--;

so the value of test.globalVar would be -1.

So either one of the if-statements get executed or both.

What actually happened:

I got 0 and 1 as output of the main method. Why do I get 0 and 1 and not 0 and -1?

Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
  • Sequence of thread execution is not guaranteed. It is on operating system mercy. – kosa Jul 30 '12 at 19:35
  • 1
    What do you mean by I got 0 and 1? Are you trying to print globalVar out somewhere else besides main's System.out.println(globalVar)? – Kevin Zhou Jul 30 '12 at 19:35
  • 3
    try joining both of the threads before printing globalVar. You're probably reaching the last line of the main method before both threads have a chance to finish. If 1 finishes you end up with 0, if neither finishes before you get there you get 1. – Mike Deck Jul 30 '12 at 19:36

4 Answers4

3

You are decrementing globalVar twice. The possible values of globalVar at the end are:

  • -1 - if everything went fine and both threads correctly decremented the value before it was printed

  • 0:

    • if only one thread managed to decrement the variable and the second one didn't manage to finish before printing it

    • if the globalVar was decremented at the same time

  • 1:

    • if System.out.println() managed to execute before both threads completed (quite probable). The globalVar was indeed modified, but after it was already printed

    • due to visibility issue main thread sees original globalVar value, not the one modified by different threads. You need some sort of synchronization or volatile keyword to see changes made by other threads immediately (or ever).

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
1

The

System.out.println(globalVar);

does not wait for the threads to complete. The threads may or may not be complete at that point. So the value can be 0, 1, or -1 depending on whether both the threads completed, one completed or both did not complete.

To have a better test,
- use Thread.sleep() in the threads to make sure that there is a delay
- Use different delays in the different threads to better visualize the race condition.
- You may want to print the value of the variable in the threads also. this way you have three threads racing (A, B and the main thread) and you get better visualizations.

Nivas
  • 18,126
  • 4
  • 62
  • 76
0

Good question. I think you need to run more tests. :-)

You might try changing your loop in the Runnable class to sleep with a random number of milliseconds (500-1000). Loop just 10 times. See if you don't get your expected race condition.

I think that most computers are just too darn fast. You're simple loop may not be doing enough work to cause a thread switch.

I love these kinds of questions because I run into bugs like this all the time.

jjohn
  • 9,708
  • 4
  • 20
  • 21
0

You can get a 1 if the value is printed before either thread has decremented the value.

Geoff Reedy
  • 34,891
  • 3
  • 56
  • 79