原子性

当我们在无状态的对象中增加一个状态时,会出现什么情况?假设我们希望增加一个“命中计数器”来统计所处理的请求数量。一种直观的方法是 在Servlet中增加一个long 类型的域,并且每处理一个请求就 将这个值加1,如下程序:

public class UnsafeCountingFactorizer implements Servlet{
    private long count=0;

    public long getCount(return count;}
   
    public void service(ServletRequest req,ServletResponse resp){
         BigInteger i=extractFromRequest(req);
         BigInteger[] factors=factor(i);
         ++count;
         encodeIntoResponse(resp,factors);
    

    }





}

 不幸的是,UnsafeCountingFactorizer并非线程安全的,尽管它在单线程中能正确运行。这个类很可能会丢失一些 更新操作。虽然递增操作++count 是一个紧凑的语法,使其看上去只是一个操作,但这个操作并非原子的,因而它并不会作为一个不可分割的操作来执行。实际上它包含三个独立的操作:读取count的值,将值加1,然后将计算结果写入count。这是一个 “读取-修改-写入”的操作序列,并且结果状态依赖于之前的状态。

在并发环境中,会发生递增操作丢失的情况,这种由于不恰当的执行时序而出现不正确的结果是一种非常重要的情况,它有一个正式的名字:竞态条件(Race condition)。

当计算的正确性取决于多个线程的交替执行时序时,那么就会发生竞态条件,换句话说,就是正确的结果要取决于运气。最常见的竞态条件类型 就是“先检查后执行(Check-Then-Act)”操作, 

猜你喜欢

转载自dbp5588.iteye.com/blog/2368371