java.util.concurrent.atomic 定義了對單一變數進行 atomic operations 的類別,所有類別都有 get 與 set methods,可讀寫 volatile variables。set 可確定會在 get 的前面先處理。
對於物件管理,如果有兩個 thread 同時做 get/set,會導致資料異常,所以通常會在 set method 加上 synchronized 來限制一次只有一個 thread 進入該 method
例如
Counter 類別的變數 c,會因為多個 thread 同時使用而異常
class Counter {
private int c = 0;
public void increment() {
c++;
}
public void decrement() {
c--;
}
public int value() {
return c;
}
}
所以會改寫為
class SynchronizedCounter {
private int c = 0;
public synchronized void increment() {
c++;
}
public synchronized void decrement() {
c--;
}
public synchronized int value() {
return c;
}
}
synchronized 可解決 multi-thread 問題,但會產生效能問題。
以 AtomicInteger 改寫
import java.util.concurrent.atomic.AtomicInteger;
class AtomicCounter {
private AtomicInteger c = new AtomicInteger(0);
public void increment() {
c.incrementAndGet();
}
public void decrement() {
c.decrementAndGet();
}
public int value() {
return c.get();
}
}
Atomic Operation
non-blocking 演算法提供了 compare-and-swap CAS 方法,可確保資料完整性。
CAS operation 使用以下三個 operands
M 要操作 operate 的記憶體位置
A 該變數期待的既有原始數值
B 需要被設定的新數值
CAS operation 可自動 atomically 從 M 到 B 更新數值,只會在 M 確認為 A 時,更新為 B
因此可不使用 synchronization lock,完成資料的更新,沒有 thread 會被 suspended,也不需要 context switching。
常用的 Atomic Variables 有 AtomicInteger, AtomicLong, AtomicBoolean, AtomicReference,分別代表 int, long, boolean, object reference 這些數值可自動被安全地更新,主要 methods 有
get()
等同於讀取 volatile variable,可直接取得其他 thread 更新的數值
incrementAndGet()
set()
等同於寫入 volatile variable
lazySet()
最終會寫入變數,但不保證可立即被其他 thread 取得。速度比 set 更快。可用在 cache,或被 gc 的資料
compareAndSet()
成功就回傳 true
weakCompareAndSetPlain(), weakCompareAndSetVolatile()
weakCompareAndSet() 已被 deprecated
References
# Atomic Variables Java Tutorial
An Introduction to Atomic Variables in Java | Baeldung
沒有留言:
張貼留言