Here, we have an Increment class which stores a variable count and a function that increments the count. In the RaceConditionsExample, we’re starting a thousand threads, each of which will invoke the increment() method. Finally, we’re waiting for all the threads to finish executing and then print out the value of the count variable.
If you run the code multiple times, you’ll notice that sometimes the final value of count is less than 1,000. To understand why this happens, let’s take two threads, Thread-x and Thread-y, as examples. The threads can execute the read write operation in any order. So, there will be a case when the order of execution is as follows.
Thread-x: Reads this.count (which is 0)
Thread-y: Reads this.count (which is 0)
Thread-x: Increments this.count by 1
Thread-y: Increments this.count by 1
Thread-x: Updates this.count (which becomes 1)
Thread-y: Updates this.count (which becomes 1)
In this case, the final value of the count variable is 1 and not 2. This is because both the threads are reading the count variable before any of them can update the value. This is known as a race condition. More specifically, a “read-modify-write” race condition.
Demonstrates modifying(incrementing) a shared storage/variable without synchronization leads to race condition (inconsitent/unexpected state)
Shows how to make avoid race conditions using synchronized
keyword in java