2012-06-26 120 views
7

根據我的理解,一個servlet容器爲每個servlet實例創建有限的servlet實例和多個線程,並重用這些線程和實例。爲什麼EJB線程安全並且servlet不是?

因爲線程有多個實例,所以它們不是「線程安全的」(儘管我明白使用線程安全編碼它們並不困難)。

另一方面,EJB容器不會創建EJB線程,而只會重用EJB對象(使用池)。由於不存在EJB實例的多個線程,因此不存在線程安全問題。

我的問題:爲什麼會有不同的行爲?將EJB作爲Servlet工作(線程不安全)不是一個好主意嗎?

我確定我錯過了一些東西,並且想要了解那些缺失的部分。

+0

他們爲什麼要一致?他們做了完全不同的事情。 – EJP

+0

@EJP,對,他們確實解決了不同的目的,但他們在無狀態方面有相似之處。有了這種相似性,EJB可以通過擁有線程而不是僅具有實例來提高性能。 –

+0

如果你對一個servlet /一個實例感興趣 - 你看看這篇文章:http://piotrnowicki.com/2012/04/one-servlet-instance-to-rule-them-all/ –

回答

8

可能是因爲他們沒有設計出相同的目標。

servlet API是一個簡單的API,非常接近HTTP協議,您可以在其上構建應用程序或框架。 HTTP協議是完全無狀態的,我認爲建立一個無狀態的API也是有意義的。在servlet API之上構建的幾個框架(例如Stripes)使用每個請求的一個Action實例,這個實例並不是同時使用的。

EJB是一個更爲複雜和高層次的框架,旨在儘可能簡單地實現事務性業務邏輯。它更重量級,並具有有狀態的組件。這些顯然需要是線程安全的。我猜想讓無狀態bean也是線程安全的是很自然的。

應該指出,例如,Spring bean默認情況下是singleton,因此必須遵循與servlet相同的規則。所以多種設計可以提供或多或少相同的功能。

線程與性能優化無關。如果您需要同時處理3個請求,則無論請求是轉到servlet還是轉到EJB,您都需要3個線程。

+2

Servlet和EJB都可以開始/提交事務,並且從Java EE 6開始,它們都可以是多線程的。這確實是EJB專家組比Servlet專家組更加保守的決定 - 直到最近幾年。在EJB 3.2中,我們完全擺脫了那些不應該超過推薦的虛假「不能使用文件」的限制,應該已經在EE規範而不是EJB規範中。 –

+0

謝謝JB的詳細解釋。據我所知,與EJB相比,Servlet通常是輕量級的。但另一方面,無狀態EJB(它是最常見的EJB類型)提供了類似的功能,並且不會存儲任何狀態。與servlet類似,EJB可以很容易地以「線程安全」的方式編寫。因爲這是可行的,創建線程比創建實例更有效。這不正確嗎? –

+2

首先,無狀態bean可以有狀態。他們不可能有會話狀態,這是非常不同的。其次,正如David Blevins在他的回答中所解釋的那樣,您可以使用與servlet類似的單例。第三,在EJB和servlet中使用線程來處理併發請求。唯一的區別是所有併發線程都使用單個servlet實例,而EJB一次只能由一個線程使用。爲什麼讓你認爲創建一個bean實例是如此昂貴?例如,使用Java創建對象比執行SQL查詢要快很多個數量級。 –

3

你最好的答案是直出的Javadoc爲javax.servlet.SingleThreadedModel接口:

已過時。從Java Servlet API 2.4開始,沒有直接替換。

public interface SingleThreadModel

確保小服務程序處理在一個時間只有一個請求。這個接口沒有方法。

如果一個servlet實現這個接口,你是保證沒有兩個線程將同時在servlet的服務方法中執行。 servlet容器可以通過同步對單個servlet實例的訪問,或者通過維護一個servlet實例池並將每個新請求分派給一個空閒servlet來實現這一保證。

請注意,SingleThreadModel 不能解決所有線程安全問題。例如,即使使用SingleThreadModel servlet,會話屬性和靜態變量仍可以同時在多個線程上通過多個請求訪問。建議開發人員採取其他方法來解決這些問題,而不是實現此接口,例如避免使用實例變量或同步訪問這些資源的代碼塊。此接口在Servlet API版本2.4中不推薦使用。

8

最簡短的回答你的問題,當然這是一個好主意,有可能使EJB來如servlet和EJB 3.1的工作,我們補充說,能做到這些組件:@Singleton

@Singleton豆可以多線程等小服務程序,或者:

  • 上的方法使用@ConcurrencyManagement(BEAN)
  • 使用@ConcurrencyManagement(CONTAINER)@Lock(READ)沿對於非線程安全的方法,需要併發性並且@Lock(WRITE)

Servlets多年來一直存在的EJB從來沒有過的另一件事是<load-on-startup>,它允許Servlet在應用程序啓動時急切加載並執行工作。

爲了配合我們添加了@Startup註釋可以添加到任何@Singleton EJB,並使其在應用程序啓動時啓動的Servlet <load-on-start>。這些bean將在應用程序啓動時調用它們的@PostConstruct方法,並在應用程序關閉時調用它們的@PreDestroy

除了使用數量(<load-on-startup>1</load-on-startup>),以決定在與@Startup開始註解的bean,你可以註釋豆@DependsOn,並指定需要註解的bean之前啓動Bean的列表的順序。

而我們在EJB 3.1中爲了對齊Servlet和EJB所做的一個鮮爲人知的理解方面當然是允許將EJB打包在.war文件中 - 這不是那麼不爲人知的部分 - 而且當我們這樣做時我們悄悄地改變了java:comp/env的定義以匹配Servlet方法。

在EJB 3.1之前,沒有辦法讓兩個EJB共享一個java:comp/env命名空間(java:comp/env在EJB規範中是bean範圍的)。相比之下,Servlet從來沒有任何方法讓單個Servlet擁有自己的專用java:comp/env名稱空間(java:comp/env在Servlet規範中是模塊範圍的)。因此,在EJB 3.1中,包裝在戰爭中的EJB與Web應用中的所有其他Servlet和EJB具有相同的模塊範圍java:comp/env命名空間,這與EJB在打包時獲得的bean範圍java:comp/env命名空間形成鮮明對比戰爭之外的EAR。我們幾周來就這個問題進行了辯論。

不錯的啤酒時間微不足道的測驗你的朋友。

+0

這對我來說是好消息,JEE6中的EJB提供多線程選項。這讓我很高興,我的理解是正確的軌道:) –

相關問題