Lock-Free Programming
High-performance concurrency without locks.
What is Lock-Free Programming?
Section titled “What is Lock-Free Programming?”Lock-free programming achieves thread-safety without using locks, using atomic operations and CAS (Compare-And-Swap) instead.
Visual: Lock-Based vs Lock-Free
Section titled “Visual: Lock-Based vs Lock-Free”CAS (Compare-And-Swap)
Section titled “CAS (Compare-And-Swap)”CAS is an atomic operation that updates a value only if it matches an expected value.
Visual: How CAS Works
Section titled “Visual: How CAS Works”CAS Pseudocode
Section titled “CAS Pseudocode”CAS(memory_location, expected_value, new_value): if memory_location.value == expected_value: memory_location.value = new_value return true # Success else: return false # Failure, retry neededJava Atomic Variables
Section titled “Java Atomic Variables”Java provides atomic variables that use CAS internally.
AtomicInteger
Section titled “AtomicInteger”import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerExample { private static AtomicInteger counter = new AtomicInteger(0);
public static void increment() { // Atomic increment (uses CAS internally) counter.incrementAndGet(); }
public static void main(String[] args) throws InterruptedException { Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) { threads[i] = new Thread(() -> { for (int j = 0; j < 1000; j++) { increment(); } }); threads[i].start(); }
for (Thread thread : threads) { thread.join(); }
System.out.println("Counter: " + counter.get()); // Always 10000 }}AtomicReference
Section titled “AtomicReference”import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceExample { static class Node { int value; Node next;
Node(int value) { this.value = value; } }
private static AtomicReference<Node> head = new AtomicReference<>();
public static void push(int value) { Node newHead = new Node(value); Node oldHead; do { oldHead = head.get(); newHead.next = oldHead; } while (!head.compareAndSet(oldHead, newHead)); // CAS }
public static void main(String[] args) { push(1); push(2); push(3);
Node current = head.get(); while (current != null) { System.out.println(current.value); current = current.next; } }}The ABA Problem
Section titled “The ABA Problem”The ABA problem occurs when a value changes from A → B → A, making CAS think nothing changed.
Visual: ABA Problem
Section titled “Visual: ABA Problem”Solution: AtomicStampedReference
Section titled “Solution: AtomicStampedReference”import java.util.concurrent.atomic.AtomicStampedReference;
public class ABASolution { public static void main(String[] args) { String initialRef = "A"; int initialStamp = 0;
AtomicStampedReference<String> ref = new AtomicStampedReference<>(initialRef, initialStamp);
// Thread 1: Read reference and stamp int[] stampHolder = new int[1]; String ref1 = ref.get(stampHolder); int stamp1 = stampHolder[0];
// Thread 2: Change A → B → A (with different stamp) ref.compareAndSet("A", "B", 0, 1); // A → B, stamp 0 → 1 ref.compareAndSet("B", "A", 1, 2); // B → A, stamp 1 → 2
// Thread 1: CAS with original stamp (fails!) boolean success = ref.compareAndSet(ref1, "C", stamp1, stamp1 + 1); System.out.println("CAS succeeded: " + success); // false (stamp mismatch!) }}Lock-Free Stack
Section titled “Lock-Free Stack”A lock-free stack using CAS:
import java.util.concurrent.atomic.AtomicReference;
public class LockFreeStack<T> { static class Node<T> { T value; Node<T> next;
Node(T value) { this.value = value; } }
private AtomicReference<Node<T>> head = new AtomicReference<>();
public void push(T value) { Node<T> newHead = new Node<>(value); Node<T> oldHead; do { oldHead = head.get(); newHead.next = oldHead; } while (!head.compareAndSet(oldHead, newHead)); // CAS }
public T pop() { Node<T> oldHead; Node<T> newHead; do { oldHead = head.get(); if (oldHead == null) { return null; } newHead = oldHead.next; } while (!head.compareAndSet(oldHead, newHead)); // CAS return oldHead.value; }}Trade-offs: Lock-Free vs Locked
Section titled “Trade-offs: Lock-Free vs Locked”| Aspect | Lock-Free | Locked |
|---|---|---|
| Performance | Higher (no blocking) | Lower (contention) |
| Complexity | Higher | Lower |
| Correctness | Harder to verify | Easier to reason about |
| Use When | High contention, performance critical | Most cases |
Interview Questions
Section titled “Interview Questions”Q1: “What is CAS and how does it work?”
Section titled “Q1: “What is CAS and how does it work?””Answer: CAS (Compare-And-Swap) is an atomic operation that:
- Compares a memory location’s value with an expected value
- If they match, updates to a new value
- Returns success/failure
- Used for optimistic locking without blocking
Q2: “Explain the ABA problem and how to solve it.”
Section titled “Q2: “Explain the ABA problem and how to solve it.””Answer: ABA occurs when value changes A→B→A, making CAS think nothing changed. Solutions:
- AtomicStampedReference: Add version/stamp to detect changes
- Tagged pointers: Add metadata to pointer
- Hazard pointers: Advanced technique for memory management
Key Takeaways
Section titled “Key Takeaways”Next Steps
Section titled “Next Steps”- Concurrency Hazards - Deadlocks, livelocks, and other pitfalls
Lock-free programming is powerful but complex—use wisely! 🚀