线程安全
Table of Contents
定义
多线程环境下 无需 调用方进行任何同步处理 也能保证正确性 , 线程安全的类无须使用者考虑同步问题
原子性
race condition
check-and-act
基于check的结果进行操作。由于check和act并非是原子的,进行act时check的结果可能已经无效
@NotThreadSafe public class LazyInitRace { private static ExpensiveObject instance = null; public static ExpensiveObject getInstance() { // if语句是一个check-and-act操作 if (instance == null) { instance = new ExpensiveObject(); } return instance; } }
read-and-modify
读取某个变量的值,修改后写回。如果B线程在A线程read之后write之前修改了变量的值,那么A线程read的结果就失效了
@NotThreadSafe public class CountingFactorizer implements Servlet { private final long count = 0; public void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); BigInteger[] factors = factor(i); // // 自增语句是一个Read‐modify‐write操作 count++; encodeIntoResponse(resp, factors); } }
使用原子变量修复
@ThreadSafe public class CountingFactorizer implements Servlet { private final AtomicLong count = new AtomicLong(0); public long getCount() { return count.get(); } public void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); BigInteger[] factors = factor(i); count.incrementAndGet(); encodeIntoResponse(resp, factors); } }
同步锁
每一个成员的操作都是原子的 ,也不能保证 所有涉及到成员的操作 整体上是 原子的
@NotThreadSafe public class UnsafeCachingFactorizer implements Servlet { private final AtomicReference<BigInteger> lastNumber = new AtomicReference<BigInteger>(); private final AtomicReference<BigInteger[]> lastFactors = new AtomicReference<BigInteger[]>(); public void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); if (i.equals(lastNumber.get())) encodeIntoResponse(resp, lastFactors.get()); else { BigInteger[] factors = factor(i); lastNumber.set(i); lastFactors.set(factors); encodeIntoResponse(resp, factors); } } }
synchronize锁
@ThreadSafe public class SynchronizedFactorizer implements Servlet { @GuardedBy("this") private BigInteger lastNumber; @GuardedBy("this") private BigInteger[] lastFactors; public synchronized void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); if (i.equals(lastNumber)) encodeIntoResponse(resp, lastFactors); else { BigInteger[] factors = factor(i); lastNumber = i; lastFactors = factors; encodeIntoResponse(resp, factors); } } }