话不多说,直接看代码
/**
* 功能实现:将请求的整数i进行因数分解,返回结果,并将该整数及其因数分解结果保存,类似于缓存的作用
*/
public class CachedFactorizer implements Servlet{
private BigInteger lastNamer;
private BigInteger[] lastFactors;
private long hits;
private long cacheHits;
public synchronized long getHits(){return hits;}
public void service(ServletRequest req, ServletResponse resp){
BigInteger i = extractFromRequest(req);
BigInteger[] factors = null;
synchronized (this){
//命中计数器,统计请求次数,因为数据共享需要同步
++hits;
//如果缓存中有
if(i.equals(lastNamer)){
//缓存命中计数器,统计调用缓存的次数
++cacheHits;
//直接返回缓存中的结果
factors = lastFactors.clone();
}
}
//如果缓存中没有,进行因数分解,将结果返回
if(factors == null){
factors = factor(i);
synchronized (this){
lastNamer = i;
lastFactors = factors.clone();
}
}
encodeIntoResponse(resp, factors);
}
}
命中计数器在这里使用的是long类型,也可以使用原子操作AtomicLong类型,但没有必要,因为即便使用AtomicLong类型也要用synchronized同步块,而且使用两种不同的同步机制不仅会带来混乱,也不会在性能或安全性上带来任何好处。
比起直接把所有内容都同步,这里选择把不影响共享状态且执行时间较长的操作从同步代码块中分离出去,即进行因数分解的计算操作factors = factor(i),可以提高程序运行的效率。