2013-05-15 21 views
0

这是与我以前的帖子在这里一姐的问题: Simple web server when high-concurrency is metServlet的问题时,高并发情况

的面试问题是:

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是单例,因此会出现同步问题。它已经声明计数器是不稳定的,这不会阻止问题。我建议同步服务方法?

回答

2

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

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

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

1

由于volatile只是告诉编译器不要优化这个变量,它不会帮助与并发有关的问题。

我不知道你会做counter因为你只是递增它什么,但我们可以肯定的是,service方法N个电话后,计数器将不等于N.

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

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"); 
}