Signatur
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
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
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));
// };
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);
// 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+.