๐Ÿ›ก️ Thread-Safe Programming in Java: Locks, Atomic Variables & LongAdder

Writing thread-safe code in Java requires understanding locks, atomic variables, and concurrent utilities. In this post, we'll explore ReentrantLock, synchronized blocks, AtomicLong, LongAdder, and when to use each.

1. ๐Ÿ”‘ Synchronized Blocks

The simplest way to make a section of code thread-safe is the synchronized keyword. It locks on an object monitor.

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

✅ Easy to use for simple critical sections

❌ Locks the entire object, can reduce concurrency

2. ๐Ÿ”„ ReentrantLock

More flexible than synchronized blocks. Supports tryLock, timed locks, and interruptible locks.

import java.util.concurrent.locks.ReentrantLock;

ReentrantLock lock = new ReentrantLock();

lock.lock();
try {
    // critical section
} finally {
    lock.unlock();
}

✅ Better for advanced locking strategies, fairness, or interruptible waits

3. ๐Ÿงช AtomicLong

Use AtomicLong or AtomicInteger for simple counters without explicit locks. Operations are atomic and thread-safe.

import java.util.concurrent.atomic.AtomicLong;

AtomicLong counter = new AtomicLong();
counter.incrementAndGet();
long value = counter.get();

✅ Lock-free atomic operations, very efficient under low to moderate contention

4. ⚡ LongAdder

For high-contention counters, LongAdder splits the counter into multiple cells to reduce contention, making it faster than AtomicLong under heavy load.

import java.util.concurrent.atomic.LongAdder;

LongAdder adder = new LongAdder();
adder.increment();
long value = adder.sum();

✅ Excellent for highly concurrent counters, like metrics or request counting

5. ๐Ÿ—️ When to Use What

  • synchronized: simple, small critical sections, low contention
  • ReentrantLock: complex locking, timed/interruptible locks, fairness required
  • AtomicLong: counters or values updated frequently, low contention
  • LongAdder: high-throughput counters under heavy multi-threading

6. ๐Ÿ”— Additional Utilities

  • ReadWriteLock: multiple readers, single writer for shared data
  • StampedLock: optimistic reads for very high-performance scenarios
  • ConcurrentHashMap: atomic per-key operations, ideal for shared maps
  • Semaphore: limits concurrent access to a resource pool

7. ๐Ÿ“Š Visual Summary

Sync

Simple object monitor

Lock

Advanced ReentrantLock

Atomic

AtomicLong / LongAdder

8. Conclusion

Java provides a rich set of tools for thread-safe programming. Choosing the right primitive — synchronized, ReentrantLock, AtomicLong, LongAdder — depends on your concurrency needs and contention levels.

Curious about modern threading and executors? Read Modern Java Concurrency: Threads, Executors & Virtual Threads.

Labels: Java, Concurrency, Locks, AtomicLong, LongAdder, ReentrantLock, Multithreading, Performance, Thread Safety

Comments

Popular posts from this blog

๐Ÿ› ️ The Code Hut - Index

๐Ÿ›ก️ Resilience Patterns in Distributed Systems