Clean • Professional
A Race Condition occurs in a multithreaded program when two or more threads access and modify shared data simultaneously, and the final result depends on the order in which the threads execute.
Because thread scheduling is controlled by the JVM and the operating system, the execution order is unpredictable, which can lead to incorrect, inconsistent, or corrupted results.
Threads are said to be “racing” to read and update the same shared resource.
As a result, the output may change every time the program runs.
classCounter {
intcount=0;
voidincrement() {
count++;// NOT thread-safe
}
}
publicclassRaceConditionDemo {
publicstaticvoidmain(String[] args)throws InterruptedException {
Countercounter=newCounter();
Threadt1=newThread(() -> {
for (inti=0; i <1000; i++) {
counter.increment();
}
});
Threadt2=newThread(() -> {
for (inti=0; i <1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count: " + counter.count);
}
}
Expected Output
Final Count:2000
Actual Output (varies each run)
Final Count:1873
Final Count:1932
The operation count++ is not atomic.
It internally performs three separate steps:
countWhen multiple threads execute these steps at the same time, updates can be lost, causing incorrect results.
A race condition occurs when all of the following are true:
Without thread safety, race conditions can cause:
Thread safety ensures that shared data remains consistent, regardless of how many threads access it.
1. Using synchronized
synchronizedvoidincrement() {
count++;
}
Ensures that only one thread can execute the critical section at a time.
2. Using Atomic Classes
AtomicIntegercount=newAtomicInteger(0);
count.incrementAndGet();
Provides lock-free, high-performance thread safety for counters and simple operations.
3. Using Locks (ReentrantLock)
lock.lock();
try {
count++;
}finally {
lock.unlock();
}
Used when fine-grained control, fairness, or advanced locking features are required.
Two ATM machines withdraw money from the same bank account at the same time:

This happens due to unsynchronized access to shared data — a classic race condition.
| Aspect | Race Condition | Thread Safety |
|---|---|---|
| Nature | A problem that arises when multiple threads access and modify shared data without proper coordination. It is an undesired concurrent behavior. | A solution that ensures shared data is accessed and modified safely in a concurrent environment. It is a desired behavior for correctness. |
| Result / Outcome | Leads to incorrect, inconsistent, or corrupted data. Program behavior becomes unpredictable and may vary across runs. | Guarantees correct, consistent, and predictable data. Program behaves reliably regardless of thread scheduling. |
| Cause / Root Reason | Occurs due to lack of synchronization, non-atomic operations, and unsafely shared mutable data. | Achieved through proper synchronization, atomic operations, or concurrency controls that prevent simultaneous unsafe access. |
| Behavior / Execution | Non-deterministic: The output can change every run depending on which thread executes first. | Deterministic: The outcome is consistent and independent of the execution order of threads. |
| Impact on Application | Can cause bugs that are hard to detect and reproduce, data corruption, or system failures, especially in critical systems like banking or ticketing. | Ensures reliable and stable program execution, prevents data corruption, and makes multithreaded code safe for production. |
| Example | Two threads increment a shared counter without locks → final count varies. | Two threads increment a shared counter using synchronized or AtomicInteger → final count is always correct. |
| Detection Difficulty | Often hard to detect because issues appear intermittently and depend on thread timing. | Easy to reason about since proper thread safety eliminates timing-related inconsistencies. |
| Developer Responsibility | Requires careful attention to shared resources; failure to handle properly causes unpredictable bugs. | Requires correct use of synchronization mechanisms; ensures safe access and avoids concurrency issues. |
A Critical Section is the part of code where shared data is accessed or modified.
count++;// critical section
If multiple threads enter the critical section at the same time without synchronization, a race condition occurs.
👉 Thread safety means protecting the critical section.
Race conditions are not only about atomicity but also about visibility.
Synchronization and atomic classes ensure:
Race conditions do not occur when:
synchronized, atomic classes, or locks to protect critical sections