0

这是与我之前的帖子相关的姐妹问题: 满足高并发时的简单 Web 服务器

面试题是:

public class CounterServlet extends HttpServlet{

 private volatile static int counter=0;

 public int getCounter()
 {
   return counter;
 }

 public void service(HttpServletRequest request
                     HttpServletResponse response) throws IOException
 {
    counter++;
    PrintWriter out=response.getWriter();
    out.write("hello");
 }

上面的代码遇到高并发会出现什么问题?我的分析是:Servlet是单例的,所以同步会有问题。它已经将计数器声明为volatile,这不会阻止问题。我建议同步服务方法?

4

3 回答 3

2

If you access a static values through multiple thread each thread can have it's local cached copy! To avoid this you can declare the variable as static volatile and this will force the thread to read each time the global value. However, volatile is not a substitute for proper synchronisation!

You need to synchronize the code, although you are simply doing an increment on the counter but that does not mean that the entire method will be atomic. There may be multiple threads incrementing it at the same time using the current value from the registers. It may lead to undesirable result.

You need to either synchronize the method or use the AtomicInteger for such a trivial operation.

于 2013-05-15T08:48:15.460 回答
1

由于 volatile 只是告诉编译器不要优化此变量,因此它无助于与并发相关的问题。

我不知道你要做什么,counter因为你只是增加它,但我们可以肯定,在 N 次调用该service方法之后,计数器将不等于 N。

为了防止它,可以使方法同步(我认为这不是正确的方法),同步某个锁定对象上的递增部分或(我认为是最合适的方法)使用 AtomicInteger 而不是 int - AtomicInteger类确保对对象的所有操作都是原子完成的。

于 2013-05-15T08:42:15.460 回答
1

您应该为此目的使用AtomicInteger。但是由于只存在一个 Servlet 实例,该实例可用于来自多个客户端的多个请求。因此,不要在 Servlet 中声明任何实例或类变量,也不要使方法同步。你可以如果您想使用原语,请执行以下操作int

public void service(HttpServletRequest request
                 HttpServletResponse response) throws IOException
{
   synchronized (CounterServlet.class) {
        count++;
    }      
   PrintWriter out=response.getWriter();
   out.write("hello");
}
于 2013-05-15T08:43:55.723 回答