前面幾篇提到的 Atomicity, Visibility 都是同步時要處理的問題
如果不處理的話可能會造成:
而解法也提過了:
但實際上有另外一個方法可以確保執行緒安全,那就是 Immutability
public final class ThreeStooges {
private final Set<String> stooges = new HashSet<String>();
public ThreeStooges() {
stooges.add("Moe");
stooges.add("Larry");
stooges.add("Curly");
}
public boolean isStooge(String name) {
return stooges.contains(name);
}
}
Final fields
透過 volatile + immutable 來達到 Thread Safe
前面我們看過用 AtomicReference 來存放階乘的運算結果以及最後的數字,但因為是兩個相關的操作,因此如果沒有用 lock,就不會是執行緒安全的,就算用 volatile 也是一樣
在這我們多了一項武器,就是 immutable object,當你有兩個以上相關聯要維護的 state 時,不妨把這些 state 包在一個 immutable holder class,如下面的範例如示:
class OneValueCache {
private final BigInteger lastNumber;
private final BigInteger[] lastFactors;
public OneValueCache(BigInteger i, BigInteger[] factors) {
lastNumber = i;
lastFactors = Arrays.copyOf(factors, factors.length);
}
public BigInteger[] getFactors(BigInteger i) {
if (lastNumber == null || !lastNumber.equals(i))
return null;
else
return Arrays.copyOf(lastFactors, lastFactors.length);
}
}
定義好了 OneValueCache 之後,我們可以再加上 volatile,如下所示:
public class VolatileCachedFactorizer implements Servlet {
private volatile OneValueCache cache = new OneValueCache(null, null);
public void service(ServletRequest req, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = cache.getFactors(i);
if (factors == null) {
factors = factor(i);
cache = new OneValueCache(i, factors);
}
encodeIntoResponse(resp, factors);
}
}