2013-05-15 42 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"); 
}