liveBook · Manning

Atomicity

As explained in Advanced Algorithms and Data Structures

An atomic operation is an operation that appears indivisible to concurrent observers, with no visible intermediate state.

Atomicity makes an operation appear indivisible to concurrent observers: no thread can see or interfere with an intermediate state. A single-threaded call creates only an illusion of atomicity; shared mutable state requires explicit synchronization. section 7.7

A cache update must preserve one coherent operation across its dependent steps:

  • Check whether the key exists and update it, or check capacity and evict an entry. section 7.7
  • Add the replacement or new entry without allowing another thread to interleave between the check and mutation. section 7.7.3

Two threads, one free cache slot

Two threads can both observe that an LFU cache is not full, then both insert without evicting. The cache may overflow or one value may overwrite the other. Synchronization makes the check-and-update sequence indivisible.

Listing 7.10 Java concurrent LFU cache set
public boolean set(Key key, Value value) {
  writeLock.lock();                                                        #1
  try {                                                                    #2
    if (this.hashTable.contains(key)) {     
      PriorityQueueNode node = this.hashTable.get(key);
      node.setValue(value);  
      return node.updatePriority(node.getCounter());
    } else  if (this.getSize() >= this.maxSize) {
      this.evictOneEntry();                                                #3
    }
    PriorityQueueNode newNode = this.elements.add(key, value, 1);
    this.hashTable.put(key, newNode);
    return true;
  } finally {                                                              #4
    writeLock.unlock();                                                    #5
  }
}

The concurrent LFU set implementation places a write lock around the entire update, including lookup, eviction, insertion, and guaranteed unlock in a finally block. section 7.7.3

How Advanced Algorithms and Data Structures covers it

How deep it goes
Explains intermediate-state interference, lock-based isolation, lock scope, and deadlock risk without developing synchronization comprehensively.
Examples
Uses an LFU cache set operation, competing threads with one free slot, synchronized cache locking, and Java concurrent collections.
What it assumes
Assumes cache operations, threads, hash tables, and priority queues while motivating synchronization through a concrete race condition.
What you can do after
Build it from scratch by enclosing dependent cache mutations in a write lock and releasing it reliably.
How it connects
Connects atomicity with concurrency, synchronization, locks, race conditions, thread safety, isolation, deadlocks, and cache data structures.

Also explained in

Compare how 13 books explain atomicity →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Advanced Algorithms and Data Structures. The section links point to the parts of the book it draws on.