InterviewHubPRO
Section Overview
Q519

Question 519 of 521

Part 8: Modern JavaScript APIs, WeakRef, Proxy & Performance (464 - 521)

100%
JavaScript Internals (521 Qs)•Part 8: Modern JavaScript APIs, WeakRef, Proxy & Performance (464 - 521)

What is the Atomics API and when should it be used?

The Atomics API provides atomic operations on SharedArrayBuffer, ensuring thread-safe access to shared memory in multi-threaded JavaScript (workers).

Basic atomic operations:

javascript
 const sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * 4);
 const view = new Int32Array(sab);

 // Atomic store - write a value
 Atomics.store(view, 0, 42);

 // Atomic load - read a value
 const value = Atomics.load(view, 0); // 42

 // Atomic add - add and return old value
 const oldValue = Atomics.add(view, 0, 10); // returns 42, view[0] is now 52

 // Atomic sub - subtract
 Atomics.sub(view, 0, 2); // view[0] is now 50

 // Atomic exchange - swap values
 const prev = Atomics.exchange(view, 0, 100); // returns 50, view[0] is now 100

 // Compare and exchange
 const replaced = Atomics.compareExchange(view, 0, 100, 200);
 // If view[0] === 100, set it to 200 and return 100
 // Otherwise, return current value

Wait and notify (worker synchronization):

javascript
 // Main thread
 const sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
 const view = new Int32Array(sab);

 worker.postMessage(sab);

 // Wait for worker to set value to 1
 Atomics.wait(view, 0, 0); // Blocks until view[0] !== 0
 console.log('Worker has finished');

 // Worker thread
 self.onmessage = function(e) {
   const view = new Int32Array(e.data);

   // Do some work
   performTask();

   // Signal completion
   Atomics.store(view, 0, 1);
   Atomics.notify(view, 0, 1); // Wake up one waiting thread
 };

Mutex implementation:

javascript
 class Mutex {
   constructor(sab, index) {
     this.sab = sab;
     this.index = index;
   }

   lock() {
     const view = new Int32Array(this.sab);
     while (true) {
       const oldValue = Atomics.compareExchange(view, this.index, 0, 1);
       if (oldValue === 0) {
         return; // Successfully acquired lock
       }
       Atomics.wait(view, this.index, 1); // Wait if locked
     }
   }

   unlock() {
     const view = new Int32Array(this.sab);
     Atomics.store(view, this.index, 0);
     Atomics.notify(view, this.index, 1);
   }
 }

 // Usage
 const mutex = new Mutex(sab, 0);
 mutex.lock();
 try {
   // Critical section
   criticalOperation();
 } finally {
   mutex.unlock();
 }

Counter with atomic operations:

javascript
 class AtomicCounter {
   constructor() {
     this.sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
     this.view = new Int32Array(this.sab);
   }

   increment() {
     return Atomics.add(this.view, 0, 1) + 1;
   }

   decrement() {
     return Atomics.sub(this.view, 0, 1) - 1;
   }

   get value() {
     return Atomics.load(this.view, 0);
   }

   set value(val) {
     Atomics.store(this.view, 0, val);
   }
 }

Available atomic operations:

javascript
 // Arithmetic
 Atomics.add(typedArray, index, value)
 Atomics.sub(typedArray, index, value)

 // Bitwise
 Atomics.and(typedArray, index, value)
 Atomics.or(typedArray, index, value)
 Atomics.xor(typedArray, index, value)

 // Memory
 Atomics.load(typedArray, index)
 Atomics.store(typedArray, index, value)
 Atomics.exchange(typedArray, index, value)
 Atomics.compareExchange(typedArray, index, expectedValue, replacementValue)

 // Synchronization
 Atomics.wait(typedArray, index, value, timeout)
 Atomics.notify(typedArray, index, count)

 // Utility
 Atomics.isLockFree(size)

When to use Atomics:

  • Sharing data between web workers
  • Implementing locks, semaphores, or other synchronization primitives
  • Building concurrent data structures
  • High-performance parallel computing
  • Avoiding race conditions in shared memory