SharedArrayBuffer & Atomics - Interactive Lab | IconVault

Watch race conditions lose increments live, fix them with Atomics.add, and learn wait/notify spinlocks. Free, in-browser.

All tools

SharedArrayBuffer & Atomics

Race conditions, wait/notify and spinlocks visualized

5 of 5 free uses left

SharedArrayBuffer status: present but not usable

Real SharedArrayBuffer needs COOP and COEP headers on the page, which this sandbox preview does not send. The race demo below therefore uses cooperative tasks on a regular buffer to show the exact same interleaving behavior, honestly labeled. The Atomics code snippets are production-ready for your own isolated page.

Race condition vs Atomics.add

Two tasks each increment a shared counter 2,000 times. Without atomicity the read-add-write steps interleave and increments are lost. Run both and compare.

task A0%
task B0%
// Two threads share one counter. counter++ is NOT atomic:
// it is read -> add 1 -> write, and threads interleave mid-step.
const shared = new Int32Array(new SharedArrayBuffer(4));

async function worker() {
  for (let i = 0; i < 2000; i++) {
    shared[0]++; // race: increments get lost
  }
}
await Promise.all([worker(), worker()]);
// Expected 4000, but shared[0] is usually much lower.
// Atomics.add executes as one indivisible step: no lost updates.
const shared = new Int32Array(new SharedArrayBuffer(4));

async function worker() {
  for (let i = 0; i < 2000; i++) {
    Atomics.add(shared, 0, 1); // atomic: always exactly 4000
  }
}
await Promise.all([worker(), worker()]);
// shared[0] === 4000, every single run.

wait / notify: sleeping instead of spinning

A spinlock that just loops on compareExchange burns CPU. Atomics.wait parks the worker until Atomics.notify wakes it. This is how high-performance worker pools and wasm threading runtimes coordinate.

// Spinlock built on Atomics.compareExchange + Atomics.wait
const LOCK = 0, UNLOCKED = 0, LOCKED = 1;
const lock = new Int32Array(new SharedArrayBuffer(4));

function acquire() {
  while (true) {
    // try to swap UNLOCKED -> LOCKED; returns the previous value
    if (Atomics.compareExchange(lock, LOCK, UNLOCKED, LOCKED) === UNLOCKED) return;
    // sleep until someone notifies, instead of burning CPU
    Atomics.wait(lock, LOCK, LOCKED);
  }
}
function release() {
  Atomics.store(lock, LOCK, UNLOCKED);
  Atomics.notify(lock, LOCK, 1); // wake one waiter
}
// NOTE: Atomics.wait only works inside Workers, never on the main thread.

Why Atomics.wait throws on the main thread

Blocking the main thread would freeze the page, so the spec forbids it: Atomics.wait is worker-only. The pattern is: main thread posts work and notifies, workers wait, compute, then notify back. Atomics.load, store, add, sub, and, or, xor, exchange and compareExchange work on any thread, including the main one.

5 of 5 free runs left. Everything runs locally in your browser.

About this tool

IconVault's SharedArrayBuffer & Atomics lab shows why counter++ is not atomic. Two tasks increment one shared counter two thousand times each: the racy version interleaves its read-add-write steps and loses increments, while the Atomics.add version lands on exactly 4000 every single run. Animated progress bars and lost-update counts make the data race concrete instead of theoretical. It is free and runs fully in your browser.

Beyond the demo, the lab teaches the coordination primitives real multithreaded JavaScript uses: Atomics.wait and Atomics.notify for parking workers instead of burning CPU, and a complete spinlock built on compareExchange, all as copyable production-ready code. An honest status panel explains the COOP/COEP headers real SharedArrayBuffer needs and why Atomics.wait is worker-only.

Frequently asked questions

Popular searches

sharedarraybuffer javascriptatomics javascriptjavascript race conditionatomics.add exampleatomics.wait notifyjavascript spinlockcross origin isolationcoop coep headersshared memory web workersjavascript multithreadingatomics.compareexchangejavascript threads shared memorywasm threads sharedarraybufferjavascript concurrency explaineddata race javascriptatomics.store loadweb workers shared memoryjavascript parallel programmingatomics.exchange examplesharedarraybuffer not definedcrossoriginisolatedcross-origin-opener-policycross-origin-embedder-policy require-corpjavascript worker threadsatomics.notify exampleatomics.wait main thread errorjavascript memory modelsequential consistency javascriptcounter++ not atomiclost updates concurrencyjavascript critical sectionmutex javascript workerslock free programming jsatomics.or and xorshared typed arraytransfer sharedarraybuffer workerpostmessage sharedarraybufferjavascript threading tutorialweb worker communicationatomics wait timeoutwake worker atomicsjavascript race condition examplehow to avoid race conditions jsatomic operations javascriptshared memory browserspectre sharedarraybuffersite isolation sharedarraybufferjavascript worker poolparallel js computationatomics tutorial

More tools

Coming soon

CLI

Coming soon

Figma plugin

Coming soon

VS Code extension

Coming soon

Chrome extension

Coming soon

AI icon generator

Coming soon

Team workspaces

Coming soon

View all 10+ tools →