Open Forem

CodeWithIshwar
CodeWithIshwar

Posted on

⚠️ Why a Simple Integer Breaks in Concurrency

A small example that completely changed how I think about shared state.


🧠 The Scenario

Consider a shared integer accessed by two threads:

  • Thread A increments (+1)
  • Thread B decrements (-1)

Expected

0
Enter fullscreen mode Exit fullscreen mode

Actual

❌ Unpredictable
Enter fullscreen mode Exit fullscreen mode

❗ The Hidden Problem

At first glance, this looks safe:

```java id="u3q9mp"
value++;




But this is **not atomic**.

It actually involves three steps:

1. Read
2. Modify
3. Write

Now imagine this execution order:



```id="s7k1ye"
Thread A β†’ Read (0)
Thread B β†’ Read (0)
Thread A β†’ Write (1)
Thread B β†’ Write (-1)
Enter fullscreen mode Exit fullscreen mode

Final result: -1 instead of 0


⚠️ Race Condition

This is a race condition:

  • Multiple threads access shared data
  • At least one modifies it
  • No synchronization is applied

Result:

  • Inconsistent state
  • Unpredictable output
  • Subtle, hard-to-debug bugs

πŸ’» Java Example

```java id="kz9r2a"
class Counter {
int value = 0;

void increment() {
    value++; // not atomic
}

void decrement() {
    value--; // not atomic
}
Enter fullscreen mode Exit fullscreen mode

}

public class Main {
public static void main(String[] args) throws Exception {
Counter counter = new Counter();

    Thread t1 = new Thread(() -> {
        for (int i = 0; i < 10000; i++) counter.increment();
    });

    Thread t2 = new Thread(() -> {
        for (int i = 0; i < 10000; i++) counter.decrement();
    });

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

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

    System.out.println(counter.value); // ❌ unpredictable
}
Enter fullscreen mode Exit fullscreen mode

}




---

## βœ… Approaches to Fix

### 1. synchronized

* Simple and reliable
* Ensures mutual exclusion
* ❌ Can reduce concurrency

---

### 2. AtomicInteger

* Lock-free
* Efficient for counters



```java id="6m2y8t"
import java.util.concurrent.atomic.AtomicInteger;

AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet();
Enter fullscreen mode Exit fullscreen mode

3. Locks (ReentrantLock)

  • Fine-grained control
  • Useful for advanced cases
  • ❌ More complex

🌐 JavaScript Perspective

Even in JavaScript, async operations can introduce similar issues:

```javascript id="r4t8zn"
let counter = 0;

async function increment() {
let temp = counter;
await Promise.resolve();
counter = temp + 1;
}

async function decrement() {
let temp = counter;
await Promise.resolve();
counter = temp - 1;
}




---

## πŸ” Coordinating Async Access (Mutex Pattern)



```javascript id="g2w9xp"
class Mutex {
  constructor() {
    this.locked = false;
    this.queue = [];
  }

  lock() {
    return new Promise(resolve => {
      if (!this.locked) {
        this.locked = true;
        resolve();
      } else {
        this.queue.push(resolve);
      }
    });
  }

  unlock() {
    if (this.queue.length > 0) {
      const next = this.queue.shift();
      next();
    } else {
      this.locked = false;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

🎯 Key Takeaway

Concurrency bugs rarely fail loudly.
They fail silentlyβ€”and that’s what makes them dangerous.


πŸš€ Closing Thought

This small example highlights a deeper principle:

Shared state + concurrency = risk unless carefully managed.


🏷️ Suggested Tags

concurrency multithreading java javascript backend


πŸ“Œ Author

Sharing practical backend learnings.

#CodeWithIshwar

Top comments (0)