Race condition in Java multi-threading

Race condition occurs in a multi-threaded environment when more than one thread try to access a shared resource (modify, write) at the same time. Note that it is safe if multiple threads are trying to read a shared resource as long as they are not trying to change it. Since multiple threads try to race each other to finish executing a method thus the name race condition.

Note that multiple threads executing inside a method is not a problem in itself, problem arises when they try to access the same resource. Examples of shared resources are class variables, DB record in a table, writing in a file.

Let’s see one example where we have a shared instance variable, as we have three threads sharing the same object of the class.

This instance variable c is incremented and decremented so every thread should leave it in the state it initially was i.e. if c is zero in the start, incrementing it will make it 1 and decrementing it will make it zero again.

Here some delay is simulated using sleep(), as in a real production system there may be many processes running and many users might be accessing the same application at any given time. In that kind of scenario we can’t be sure of when context switching will happen among the threads contending for CPU-cycle. That’s why race condition related bugs are very difficult to find and you may not be even able to reproduce them as that kind of context-switching may not happen when you are trying to reproduce the race condition related error.

Example:

Output:

Value for Thread After increment Thread-1 1
Value for Thread at last Thread-1 1
Value for Thread After increment Thread-2 2
Value for Thread at last Thread-2 0
Value for Thread After increment Thread-3 1
Value for Thread at last Thread-3 0

It can be seen how the shared variable counter is giving wrong values.

To fix the race condition we need to have a way to restrict resource access to only one thread at a time. We have to use  synchronized keyword to synchronize the access to the shared resource. Let’s see the same example again with proper synchronization to avoid race condition.

Output:

Value for Thread After increment Thread-1 1
Value for Thread at last Thread-1 0
Value for Thread After increment Thread-3 1
Value for Thread at last Thread-3 0
Value for Thread After increment Thread-2 1
Value for Thread at last Thread-2 0

 

It can be seen from the output how threads are accessing the shared resource one at a time now. Synchronizing the access with in the run() method made it happen.

Points to note –

  • A code block that has a shared resource and may lead to race conditions is called a critical section.
  • Race conditions can be avoided by proper thread synchronization in critical sections.

 

   

Share :Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

Comments are closed