2.2 原子性

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

程序清单2-2 在没有同步的情况下统计已处理请求数量的Servlet(不要这么做)

@NotThreadSafe

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

Get Java并发编程实战 now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.