2014-12-06 15 views
1
public class ExampleServlet extends HttpServlet{ 

    private Closure closure; 

    @Override 
    protected void doPost(final HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
     // Do some stuff here... 
     if (this.closure == null){ 
      this.closure = new Closure(){ 
       @Override 
       public void someFunction(){ 
        req.getRequestURI(); // Obviously do something with it... 
       } 
      } 
     } 

     // Later... 
     this.closure.someFunction(); // << Is this thread-save?? 

     // More stuff here... 
    } 
} 

在這個例子中,我有過Closure管不着!這是否緩存關閉線程保存?

如果我測試這個,它工作正常。現在的問題是:

是否每個請求的線程得到closure已場內的一個新副本?否則,當有新的請求進入時,引用的req字段將會改變,而someFunction()仍在執行。或者這是通過宣佈reqfinal來處理的?

+0

的'如果(this.closure == NULL){..},因爲它需要同步'的部分是不是安全:) – zapl 2014-12-06 00:49:30

回答

3

所有請求都使用相同的servlet實例。

因此,閉包將僅爲第一個請求創建,並在所有後續請求之間共享。

它會繼續引用命中servlet的初始請求,因此根本不應該工作,即使沒有多線程(單線程順序請求也被中斷)。

如果你有多個線程,你獲得額外的併發症,比如必須在servlet實例爲「懶單初始化」部分同步。理想情況下,所有這些初始化都是在servlet的init方法中完成的。

難道你不能讓它成爲doPost的局部變量嗎?

是否每個請求線程都獲得閉包字段的新副本?

不是。它們全部共享相同的servlet及其(單個)閉包字段。

當有新的請求進來時,引用的req字段會在someFunction()仍在執行時發生變化。

否。捕獲的req在封閉的生命週期內不會改變。它是final,並在首次創建閉包時從Servlet中複製。它將繼續引用打到servlet的第一個請求。

或者這通過聲明REQ作爲最終處理?

由於how closures in Java are implemented的性質,這是技術要求。它們並不真正捕獲變量,它們捕獲變量的快照值作爲副本。

+0

你實際上對,代碼工作,因爲它是在基類中實際的servlet。所以實際上每個Servlet都有一個實例。而且方法中的邏輯不需要每次重新評估,所以結果也是有意義的。謝謝澄清! – 2014-12-06 02:34:45

+0

@LukasKnuth:那非常脆弱。例如,您可以將相同的Servlet映射到多個URL模式。我想象會破壞你的代碼。嘗試將此配置移動到init方法中。 – Thilo 2014-12-06 02:53:25

+1

我現在每次調用都重新創建閉包,這不是那麼多的開銷,我完全理解代碼;) – 2014-12-06 16:51:18