程序清单1-1非线程安全的数值序列生成器
import net.jcip.annotations.NotThreadSafe; @NotThreadSafe public class UnsafeSequence { private int value; /*返回一个唯一的数值*/ public int getValue() { return value++; //三个操作:读取,加一,赋值。 多线程并发操作value可能导致步骤被打乱 } }
程序清单1-2 线程安全的数值序列生成器
public class Sequence { private int value; /*返回一个唯一的数值*/ public synchronized int getValue() { //各个线程串行访问 return value++; } }
程序清单2-1 一个无状态的Servlet ,各个线程间没有共享状态
@ThreadSafe public class StatelessFactorizer implements Servlet{ public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { BigInteger i = extractFromRequest(req); BigInteger[] factories = factor(i); encodeIntoResponse(res,factories); } }
程序清单2-3 延迟初始化中的竞态条件(不要这么做)
@NotThreadSafe public class LazyInitRace { private ExpensiveObject instance = null; //竞态条件 public ExpensiveObject getInstance() { if(instance == null) instance = new ExpensiveObject(); return new ExpensiveObject(); } } class ExpensiveObject{}
程序清单2-4 使用AtomicLong类型的变量来统计已处理请求的数量
/*servlet的状态就是计数器count的状态,count是线程安全的,所以servlet是线程安全的*/ public class CountingFactorizer implements Servlet { private final AtomicLong count = new AtomicLong(0); //原子变量类,实现在数值和对象引用上的原子状态转换 public long getCount() { return count.get(); } public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { BigInteger i = extractFromReqest(req); BigInteger[] factors = factor(i); count.incrementAndGet(); encodeIntoResponse(res,factors); } }
程序清单2-5 该Servlet在没有足够原子性保证的情况下对其最近计算结果进行缓存(不要这么做)
/** * 因数分解: * 在数学中,因数分解,又称素因数分解,是把一个正整数写成几个约数的乘积。例如,给出45这个数,它可以分解成3×3×5,根据算术基本定理,这样的分解结果应该是独一无二的 * * * 希望提升Servlet性能,将最近的计算结果缓存起来,当2个连续的请求对相同的数值进行因数分解时,可以直接使用上一次的计算结果. * * 原子引用本身是线程安全的,但是业务逻辑中存在竞态条件 : * lastFactors[0] * lastFactors[1] * ..... = lastNumber; 此条件不被破坏,Servlet才是线程安全的。 */ public class UnsafeCachingFactorizer implements Servlet { //lastNumber、lastFactors本身是线程安全的 private final AtomicReference<BigInteger> lastNumber = new AtomicReference<BigInteger>(); //上一次请求的 因数 private final AtomicReference<BigInteger[]> lastFactors = new AtomicReference<BigInteger[]>(); //上一次请求的 因数分解结果 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { BigInteger i = extractFromReqest(req); if(i.equals(lastNumber)){ encodeIntoResponse(res,lastFactors.get()); } else { BigInteger[] factors = factor(i); lastNumber.set(i); //无法保证同时与lastFactors更新, lastFactors.set(factors); //无法保证同时与lastNumber更新 encodeIntoResponse(res,factors); } } }