首先直接上代码:(下面是一段Servlet代码)
public long getCount(){
return count;
}
public void service(ServletRequest req , ServletResponse resp){
BigInteger i = extraceFromRequst(req);
//...事务处理代码
++ count;
//....
}
上面这个代码是为了统计有多个次访问了Servlet。但是该类是线程不安全的,因为++count看上去只是一个操作,其实是分三步的:读取-修改-写入 ,并且结果状态依赖于之前的状态。所以,当两个线程A和B同时读取到了count的值,那么接下来A修改count后,B的值已经是A修改前读到的值,所以此时的数据就会不准确。这也就是竞态条件。
**静态条件:当某个计算的正确性取决于多个线程的交替执行时,那么就会出现静态条件。**
public class LazyInitRace {
private Demo demo = null;
public Demo getDemo(){
if(demo == null){
demo = new Demo();
}
return demo;
}
}
上面这段代码也是线程不安全的。例如A和B两个线程同时访问这个代码就会出现读取错误。例如A线程进入了getDemo方法,判断了demo==null,而恰巧此时B线程也到了这一步,所以此时就会创建两个demo对象。这就出现了线程不安全的现象。
上面使用的是延迟初始化静态条件,就是先判断demo是否已经被初始化,然后再初始化。由于缺少原子性操作,所以,线程是不安全的。
所以我么应该对这个代码进行原子性操作。也就是对demo所有的操作封装成一个原子,也就是只能被一个线程同时访问。
**所谓原子操作是指,对于访问同一状态的所有操作(包括操作本身)来说,这个操作是一个以原子方式执行的操作**
而这段代码想要实现线程安全其实加一个synchronized就行了。如下:
public synchronized Demo getDemo(){
if(demo == null){
demo = new Demo();
}
return demo;
}