有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

发生高并发时的java Servlet问题

这是一个姐妹问题,与我之前的帖子相关: Simple web server when high-concurrency is met

面试问题是:

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是单例的,因此在同步中会出现问题。它已将计数器声明为易失性,这不会阻止问题的发生。我建议同步服务方法


共 (3) 个答案

  1. # 1 楼答案

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

    public void service(HttpServletRequest request
                     HttpServletResponse response) throws IOException
    {
       synchronized (CounterServlet.class) {
            count++;
        }      
       PrintWriter out=response.getWriter();
       out.write("hello");
    }
    
  2. # 2 楼答案

    如果您通过多个线程访问静态值,则每个线程都可以拥有其本地缓存副本!为了避免这种情况,可以将变量声明为static volatile,这将强制线程每次读取全局值。然而,volatile并不能代替正确的同步

    您需要同步代码,尽管您只是在计数器上执行增量操作,但这并不意味着整个方法将是原子的。可能有多个线程使用寄存器中的当前值同时递增。这可能会导致不良结果

    您需要synchronize该方法或使用AtomicInteger进行这样一个简单的操作

  3. # 3 楼答案

    因为volatile只是告诉编译器不要优化这个变量,所以它不会帮助解决与并发性相关的问题

    我不知道您将如何处理counter,因为您只是在递增它,但我们可以确定,在调用service方法N次之后,计数器将不等于N

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