Start · Sprachen · JavaScript · Referenz · Atomics

Atomics

Klasse

Das <code>Atomics</code>-Namensraumobjekt stellt statische Methoden für atomare Operationen auf <code>SharedArrayBuffer</code>-Instanzen bereit, sodass mehrere Threads sicher auf geteilten Speicher zugreifen können.

seit JavaScript ES2017 Kategorie: core

Signatur

Atomics

Beschreibung

Atomics ist kein Konstruktor, sondern ein statisches Namensraumobjekt (ähnlich wie Math), das ausschließlich statische Methoden enthält. Es wurde mit ES2017 eingeführt, um sichere Mehrthread-Programmierung in JavaScript zu ermöglichen – insbesondere im Zusammenspiel mit SharedArrayBuffer und Web Workers. Alle Methoden operieren direkt auf einem TypedArray, das auf einem SharedArrayBuffer basiert, und garantieren, dass Lese-, Schreib- und Änderungsoperationen atomar – also unteilbar – ausgeführt werden.

Atomare Operationen verhindern sogenannte Race Conditions: Wenn zwei Worker gleichzeitig denselben Speicherbereich lesen und schreiben würden, könnten inkonsistente Zustände entstehen. Atomics-Methoden stellen sicher, dass zwischen Lesen und Schreiben kein anderer Thread eingreifen kann. Typische Anwendungsfälle sind Mutexe (gegenseitiger Ausschluss), Zähler, Semaphoren und andere Synchronisationsmuster in Multi-Worker-Anwendungen.

Wichtige Methoden im Überblick: Atomics.add(), Atomics.sub(), Atomics.and(), Atomics.or(), Atomics.xor() für arithmetische/bitweise Operationen; Atomics.load() und Atomics.store() für sicheres Lesen/Schreiben; Atomics.exchange() und Atomics.compareExchange() für bedingte Tauschoperationen; sowie Atomics.wait() und Atomics.notify() für die Thread-Synchronisation (Warten und Benachrichtigen).

Zu beachten ist, dass Atomics.wait() im Haupt-Thread des Browsers blockiert und dort daher nicht erlaubt ist – es darf nur in Worker-Threads verwendet werden. Seit ES2020 steht Atomics.waitAsync() als nicht-blockierende Alternative zur Verfügung. Außerdem können Atomics-Methoden nur auf Integer-TypedArrays (Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, BigInt64Array, BigUint64Array) angewendet werden, die auf einem SharedArrayBuffer basieren.

Rückgabewert

Typ
void
Beschreibung
Atomics ist kein Konstruktor und gibt keinen Wert zurück. Der Versuch, es mit new Atomics() aufzurufen, wirft einen TypeError.

Beispiele

Atomares Lesen und Schreiben mit SharedArrayBuffer

// Gemeinsamer Speicher: Int32Array auf SharedArrayBuffer
const sab = new SharedArrayBuffer(4); // 4 Bytes = 1 Int32
const sharedArray = new Int32Array(sab);

// Atomar einen Wert schreiben
Atomics.store(sharedArray, 0, 42);
console.log('Gespeicherter Wert:', Atomics.load(sharedArray, 0));

// Atomar addieren und alten Wert zurückbekommen
const vorher = Atomics.add(sharedArray, 0, 8);
console.log('Wert vor Addition:', vorher);    // 42
console.log('Wert nach Addition:', Atomics.load(sharedArray, 0)); // 50

// Bedingter Tausch (Compare-and-Swap)
const erwartet = 50;
const neuerWert = 100;
const alterWert = Atomics.compareExchange(sharedArray, 0, erwartet, neuerWert);
console.log('CAS alter Wert:', alterWert); // 50 (Tausch erfolgreich)
console.log('Neuer Wert:', Atomics.load(sharedArray, 0)); // 100
Gespeicherter Wert: 42 Wert vor Addition: 42 Wert nach Addition: 50 CAS alter Wert: 50 Neuer Wert: 100

Einfacher Mutex mit Atomics.wait() und Atomics.notify() (Worker)

// === Haupt-Thread (main.js) ===
const sab = new SharedArrayBuffer(4);
const lock = new Int32Array(sab);
Atomics.store(lock, 0, 0); // 0 = frei

const worker = new Worker('worker.js');
worker.postMessage(sab);

setTimeout(() => {
  console.log('[Haupt] Benachrichtige Worker...');
  Atomics.store(lock, 0, 1);   // Signal setzen
  Atomics.notify(lock, 0, 1);  // Einen wartenden Worker aufwecken
}, 1000);

// === worker.js ===
// self.onmessage = (event) => {
//   const lock = new Int32Array(event.data);
//   console.log('[Worker] Warte auf Signal...');
//   Atomics.wait(lock, 0, 0);  // Blockiert, bis Wert != 0
//   console.log('[Worker] Signal empfangen:', Atomics.load(lock, 0));
// };
[Haupt] Benachrichtige Worker... [Worker] Warte auf Signal... [Worker] Signal empfangen: 1

Atomics.waitAsync() im Haupt-Thread (ES2020)

// waitAsync blockiert NICHT – kann im Haupt-Thread verwendet werden
const sab = new SharedArrayBuffer(4);
const arr = new Int32Array(sab);
Atomics.store(arr, 0, 0);

const result = Atomics.waitAsync(arr, 0, 0, 2000); // Timeout 2 Sekunden
console.log('async?', result.async); // true, wenn Promise

if (result.async) {
  result.value.then((status) => {
    console.log('Wait-Status:', status); // 'ok' oder 'timed-out'
  });
}

// Nach 500ms: Worker oder Timer benachrichtigt
setTimeout(() => {
  Atomics.store(arr, 0, 1);
  const notified = Atomics.notify(arr, 0, 1);
  console.log('Benachrichtigte Waiter:', notified); // 1
}, 500);
async? true Benachrichtigte Waiter: 1 Wait-Status: ok

// Wichtig · Fallstricke

Sicherheitshinweis (Spectre): Nach der Entdeckung der Spectre-Sicherheitslücke im Jahr 2018 wurde SharedArrayBuffer (und damit Atomics) vorübergehend in allen Browsern deaktiviert. Seit 2020 ist es wieder verfügbar, erfordert aber Cross-Origin Isolation: Der Server muss die HTTP-Header Cross-Origin-Opener-Policy: same-origin und Cross-Origin-Embedder-Policy: require-corp senden. Ohne diese Header ist SharedArrayBuffer in Browsern nicht verfügbar.

Einschränkungen: Atomics.wait() darf im Haupt-Thread nicht aufgerufen werden und wirft dort einen TypeError. Als Alternative steht Atomics.waitAsync() (ES2020) zur Verfügung. Atomics-Methoden funktionieren ausschließlich mit Integer-TypedArrays auf SharedArrayBuffer – Float-Arrays und normale ArrayBuffer werden nicht unterstützt.

Browser-Kompatibilität: Atomics ist in allen modernen Browsern (Chrome 68+, Firefox 78+, Safari 15.2+, Edge 79+) sowie Node.js 8.10+ verfügbar. Atomics.waitAsync benötigt Chrome 87+, Node.js 16+.