← Back to Questions
Java

What is race condition in Java?

Learn What is race condition in Java? with simple explanations, real-time examples, interview tips and practical use cases.

What is Race Condition in Java?

A race condition in Java occurs when multiple threads access and modify shared data simultaneously, and the final result depends on the unpredictable timing of thread execution.

In simple words:

Race condition happens when multiple threads compete to update the same resource without proper synchronization, causing inconsistent or incorrect results.


Why Race Condition Happens?

Race conditions occur because:

  • Threads run concurrently
  • Threads share common resources
  • Operations are not atomic
  • No synchronization is used

Race Condition Overview Diagram


Thread 1 Reads Value

                |

                v

Shared Variable = 100

                ^

                |

Thread 2 Reads Same Value

      |
      v

Both Threads Modify Data Simultaneously

      |
      v

Incorrect Final Result


Real-World Analogy

Imagine:

  • Two people editing the same bank account balance at the same time
  • One deposit may overwrite another update

Bank Account Example


Initial Balance = 1000

      |
      +-------> Thread 1 Withdraws 200

      |
      +-------> Thread 2 Withdraws 300

      |
      v

Incorrect Final Balance Possible


Simple Race Condition Example

class Counter {

    int count = 0;

    public void increment() {

        count++;

    }

}

What Happens Internally?

count++ is NOT atomic.

Internally it performs:


1. Read current value
2. Increment value
3. Write updated value


Internal Execution Flow


Thread 1 Reads count = 5

Thread 2 Reads count = 5

      |
      v

Thread 1 Writes 6

Thread 2 Writes 6

      |
      v

Expected = 7

Actual = 6


Race Condition Demonstration

class Counter {

    int count = 0;

    public void increment() {

        count++;

    }

}

public class Main {

    public static void main(
        String[] args
    ) throws Exception {

        Counter counter =

            new Counter();

        Thread t1 = new Thread(() -> {

            for(int i = 0;
                i < 1000;
                i++) {

                counter.increment();

            }

        });

        Thread t2 = new Thread(() -> {

            for(int i = 0;
                i < 1000;
                i++) {

                counter.increment();

            }

        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println(
            counter.count
        );

    }

}

Expected Output

2000

Actual Output May Be

1785
1932
1991

Why Output Changes?

Because thread execution order is unpredictable.


Race Condition Flow


Multiple Threads Access Shared Data

      |
      v

Threads Read Same Value Simultaneously

      |
      v

Threads Overwrite Each Other

      |
      v

Data Corruption Happens


How to Prevent Race Condition?

  • synchronized keyword
  • Locks
  • Atomic classes
  • Concurrent collections
  • Immutable objects

Solution Using synchronized

class Counter {

    int count = 0;

    public synchronized void increment() {

        count++;

    }

}

How synchronized Solves Problem?

Only one thread can execute synchronized method at a time.


Synchronization Flow


Thread 1 Enters Critical Section

      |
      v

Thread 2 Waits

      |
      v

Thread 1 Finishes

      |
      v

Thread 2 Continues


What is Critical Section?

Critical section is the code block accessing shared resources.


Example

count++;

Using synchronized Block

public void increment() {

    synchronized(this) {

        count++;

    }

}

Using ReentrantLock

import java.util.concurrent.locks.*;

class Counter {

    private Lock lock =

        new ReentrantLock();

    int count = 0;

    public void increment() {

        lock.lock();

        try {

            count++;

        }
        finally {

            lock.unlock();

        }

    }

}

Using AtomicInteger

Modern Java provides atomic classes for thread-safe operations.


AtomicInteger Example

import java.util.concurrent.atomic.*;

AtomicInteger count =

    new AtomicInteger();

count.incrementAndGet();

Why AtomicInteger Better?

  • Thread-safe
  • Lock-free operations
  • High performance
  • Efficient concurrency

Race Condition vs Deadlock

Feature Race Condition Deadlock
Problem Incorrect Data Threads Stuck Forever
Cause Concurrent Modification Circular Waiting
Effect Data Corruption Application Freeze

Race Condition in Banking Systems

Banking systems are highly vulnerable to race conditions because:

  • Multiple transactions update same account
  • Balance consistency is critical
  • Concurrent withdrawals may corrupt balances

Banking Race Condition Flow


ATM 1 Reads Balance = 1000

ATM 2 Reads Balance = 1000

      |
      v

Both Withdraw Simultaneously

      |
      v

Incorrect Balance Stored


Banking Solution

  • Database transactions
  • Locks
  • Synchronization
  • Atomic operations

Race Condition in E-Commerce Systems

E-commerce platforms face race conditions in:

  • Inventory updates
  • Order processing
  • Coupon usage
  • Payment processing

E-Commerce Example


Product Stock = 1

      |
      +-------> Customer A Buys Product

      |
      +-------> Customer B Buys Product

      |
      v

Overselling Happens


Race Condition in Spring Boot

Spring Boot applications may encounter race conditions in:

  • Singleton beans
  • Shared caches
  • Concurrent API processing
  • Async tasks
  • Distributed services

Spring Boot Flow


Multiple REST Requests Arrive

      |
      v

Shared Service Object Modified

      |
      v

Race Condition Possible


Race Condition in Microservices

Distributed microservices face race conditions in:

  • Distributed transactions
  • Event processing
  • Shared distributed caches
  • Inventory synchronization
  • Kafka consumers

Microservice Flow


Service A Updates Data

Service B Updates Same Data

      |
      v

Distributed Race Condition Occurs


How Distributed Systems Prevent Race Conditions?

  • Distributed locks
  • Optimistic locking
  • Pessimistic locking
  • Versioning
  • Database transactions

Advantages of Preventing Race Conditions

  • Data consistency
  • Reliable systems
  • Correct calculations
  • Stable enterprise applications
  • Safe concurrent processing

Disadvantages of Excessive Synchronization

  • Reduced performance
  • Thread contention
  • Deadlock risk
  • Lower scalability

Common Interview Mistake

Many developers think primitive operations are always atomic.

Actually:

  • Operations like count++ are NOT atomic.

Another Common Mistake

Many developers think synchronized completely removes concurrency issues.

Actually:

  • Improper synchronization can still create bugs or deadlocks.

Best Practices

  • Use synchronization carefully
  • Prefer atomic classes when possible
  • Minimize shared mutable state
  • Use immutable objects
  • Use thread-safe collections
  • Monitor concurrency issues in production

Realtime Enterprise Example

Online Ticket Booking Platform


Available Seats = 1

      |
      +-------> User A Books Seat

      |
      +-------> User B Books Same Seat

      |
      v

Double Booking Happens

      |
      v

Race Condition Occurred


Related Learning Topics


Professional Interview Answer

A race condition in Java occurs when multiple threads concurrently access and modify shared mutable data without proper synchronization, causing unpredictable or incorrect results depending on thread execution timing. Race conditions commonly occur because operations such as incrementing variables are not atomic and involve multiple internal steps like read, modify, and write. Java provides several mechanisms to prevent race conditions including synchronized methods, synchronized blocks, ReentrantLock, AtomicInteger, thread-safe collections, immutable objects, and concurrent utilities. Enterprise applications, banking systems, Spring Boot applications, distributed microservices, Kafka consumers, e-commerce platforms, cloud-native architectures, and high-concurrency systems must carefully handle race conditions to ensure data consistency, transactional integrity, and reliable concurrent processing. Modern distributed systems additionally use optimistic locking, pessimistic locking, distributed transactions, and distributed locking mechanisms to prevent race conditions across multiple services and databases.


Frequently Asked Questions

What is race condition in Java?

Race condition occurs when multiple threads modify shared data concurrently without proper synchronization.

Why does race condition happen?

Because thread execution timing is unpredictable and shared data is accessed concurrently.

How can race conditions be prevented?

Using synchronized, locks, atomic classes, and thread-safe programming techniques.

Is count++ atomic in Java?

No, count++ is not atomic.

Where are race conditions common?

Banking systems, Spring Boot applications, distributed microservices, e-commerce platforms, and concurrent enterprise systems.

Why this Java question is important?

This interview question helps candidates understand real-time backend development concepts, practical problem solving, coding fundamentals, system design basics and production-ready application behavior.

Practice this question carefully for Java backend roles, Spring Boot developer interviews, microservices interviews, company interviews and full-stack developer preparation.

About the Author

Naresh Kumar is a Senior Java Backend Engineer with experience building enterprise applications using Java, Spring Boot, Microservices, Docker, Kubernetes and Cloud technologies.