/** * 該類無任何屬性域,且不包含任何其餘類中域的引用 * 即計算中的狀態都爲臨時狀態,保存在線程棧中 * 由JMM知線程棧線程私有,僅由當前線程可訪問 * 所以線程安全 */ @ThreadSafe public class StatelessFactorizer implements Servlet { @Override public void service(ServletRequest req, ServletResponse repo) { Map<String, Object> params = extractFromRequest(req); Map<String, Object> res = doBussiness(params); reponseTo(res); } ... }
看一個非線程安全的版本: java
/** * 競態條件(因爲不恰當的執行時序而出現不正確的結果)致使非線程安全 */ @NotThreadSafe public class UnsafeCountingFactorizer implements Servlet { private long count = 0; @Override public void service(ServletRequest req, ServletResponse repo) { count++; //該操做並不是原子(讀取--自增--寫入), 致使非線程安全 Map<String, Object> params = extractFromRequest(req); Map<String, Object> res = doBussiness(params); reponseTo(res); } }例如這種狀況,預計值爲11,結果爲10:
看個實例: 緩存
/** * 延遲初始化的競態條件 * 因爲多個線程可能同時執行到instance == null, * 或者因爲實例初始化過程比較耗費時間, * 這樣有可能所謂的"單例"再也不單例 */ @NotThreadSafe public class LazyInitRace { private ExpensiveObject instance; private LazyInitRace(){} public ExpensiveObject getInstance() { if (instance == null) { instance = new ExpensiveObject(); } return instance; } }
/** * 可經過java提供的原子變量(Atomic*) * 來解決競態條件引發的非線程安全 */ @ThreadSafe public class CountingFactorizer implements Servlet { private AtomicLong count = new AtomicLong(0); @Override public void service(ServletRequest req, ServletResponse repo) { count.incrementAndGet(); //原子增長,該方法最後會調用Unsafe.compareAndSwapLong本地方法 Map<String, Object> params = extractFromRequest(req); Map<String, Object> res = doBussiness(params); reponseTo(res); } ... }
/** * 多個關聯線程安全的狀態對象致使線程安全 * 這裏咱們對lastNumber進行緩存,若請求的值與其相同,直接返回,反之計算 */ @NotThreadSafe public class UnsafeCachingFactorizer implements Servlet { private final AtomicReference<BigInteger> lastNumber = new AtomicReference<>(); private final AtomicReference<BigInteger[]> lastFactors = new AtomicReference<>(); @Override public void service(ServletRequest req, ServletResponse repo) { BigInteger i = extractFromRequest(req); //A線程發現不等,從新計算;(A未計算完) //B線程進入也發現不等,也從新計算(但其實有可能通過A計算後是相等的) //從而達不到緩存效果 if (i.equals(lastNumber.get())){ reponseTo(i, lastFactors); } else{ BigInteger[] factors = factor(i); lastNumber.set(i); lastFactors.set(factors); reponseTo(i, factors); } } ... }
/** * 經過synchronized實現線程安全,但性能低下 */ @ThreadSafe public class CachingFactorizer implements Servlet { private BigInteger lastNumber = new BigInteger(""); private BigInteger[] lastFactors = new BigInteger[]{}; @Override public synchronized void service(ServletRequest req, ServletResponse repo) { BigInteger i = extractFromRequest(req); if (i.equals(lastNumber)){ reponseTo(i,lastFactors); } else{ BigInteger[] factors = factor(i); lastNumber = i; lastFactors = factors; reponseTo(i, factors); } } }
/** * 經過分段synchronized提高性能 */ @ThreadSafe public class CachedFactorizer implements Servlet { private BigInteger lastNumber = new BigInteger(""); private BigInteger[] lastFactors = new BigInteger[] {}; private long hits; private long cacheHits; @Override public void service(ServletRequest req, ServletResponse repo) { BigInteger i = extractFromRequest(req); BigInteger[] factors = null; synchronized (this) { ++hits; if (i.equals(lastNumber)) { ++cacheHits; factors = lastFactors; } } if (factors == null) { factors = factor(i); synchronized (this) { lastNumber = i; lastFactors = factors; } } reponseTo(i, lastFactors); } ... }
不吝指正。 安全