注:本文为笔者阅读《JAVA并发编程实战》(Brian Goetz等注)一书的学习笔记,如有错漏,敬请指出。
线程安全的界定:当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步、在调用代码方无须作其他协调,这个类的行为依然是正确的,称这个类是线程安全的。(我的理解:找不出并行执行与串行执行结果相异的情况)
构建并发程序要正确使用线程和锁。编写线程安全的代码,本质上是管理对状态的访问,而且通常是共享、可变的状态。
一般而言,一个对象的状态就是它的数据(存储在状态变量中),还包括其他附属对象的域,包含任何会对它外部可见行为产生影响的数据。
线程安全的性质取决于程序如何使用对象,而不是对象完成了什么。
注意:
以下是利用Servlet进行简单的因数分解操作的程序。
public class StatelessFactorizer implements Servlet {
public void service(ServletRequest req, ServletResponse resp){
BigInteger i=extractFromRequest(req);
BigInteger[] factors=factor(i);
encodeIntResponse(resp,factors);
}
}
(注:这段代码似乎要自己编写extractFromRequest()和encodeIntResponse()方法)
缓存最新请求和结果的servlet
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import net.jcip.annotations.GuardedBy;
import java.math.BigInteger;
public class CachedFactorizer {
@GuardedBy("this") private BigInteger lastNumber;
@GuardedBy("this") private BigInteger[] lastFactors;
@GuardedBy("this") private long hits;
@GuardedBy("this") private long cacheHits;
public synchronized long getHits(){return hits;}
public synchronized double getCacheHitRatio(){
return (double) cacheHits/(double)hits;
}
public void service(ServletRequest req, ServletResponse resp){
BigInteger i=extractFromRequest(req);
BigInteger [] factors=null;
synchronized (this){
++hits;
if(i.equals(lastNumber)){
++cacheHits;
factors=lastFactors.clone();
}
}
if(factors==null){
factors=factor(i);
synchronized (this){
lastNumber=i;
lastFactors=factors.clone();
}
}
encodeIntResponse(resp,factors);
}
}