点击计数器Servlet

时间:2011-03-26 17:02:02

标签: servlets thread-safety

即使不涉及“检查并执行”操作,也可能发生竞争条件,例如,在以下代码中,十个请求将导致十个线程,但此后计数器不保证为10。首先,我说对了吗?

private int numPageHits;   
public void doGet(HttpServletRequest request, 
                                 HttpServletResponse response) 
                                       throws IOException, ServletException 
    { 
       //this method executes whenever the servlet is hit 
       //increment numPageHits 
       numPageHits++; 
    }

一种解决方案可能是使用同步块,如:

synchronize(this) {
    numPageHits++; 
}

我只是想知道是否有另一种处理这种情况的方法?

由于

3 个答案:

答案 0 :(得分:3)

答案 1 :(得分:1)

正如 pajton 建议的那样,使用AtomicIntegerAtomicLongincrementAndGet()方法会更好。

没有synchronized的代码不仅是竞争条件的主题,还引入了线程可见性问题。请参阅volatile关键字。

答案 2 :(得分:0)

你是对的。 ++不是原子操作(即使它看起来像是这样),因此需要通过JVM / Java内存模型重新排序优化和线程上下文切换。

++在技术上是一个3个操作“get-and-set”: 1)检索当前值 2)将值加1 3)存储新值

线程上下文切换可以出现在这3个步骤中的任何位置,导致每个线程在任何给定的时间点看到diff值。

正如其他人所指出的那样,这是Atomics的完美候选者。这是关于这个主题的一个很好的链接:http://www.javamex.com/tutorials/synchronization_concurrency_7_atomic_updaters.shtml

使计数器变量不稳定在这里是不够的,因为新值取决于旧值,因此受上下文切换引起的竞争条件的影响。这是另一个很好的链接:http://www.ibm.com/developerworks/java/library/j-jtp06197.html

这是一个非常常见的面试问题,顺便说一句......