为什么EJB线程安全且servlet不安全?

San*_*dal 7 java multithreading servlets ejb thread-safety

根据我的理解,servlet容器创建有限的servlet实例和每个servlet实例的多个线程,并重用这些线程和实例.

因为有多个线程实例,所以它们不是"线程安全的"(虽然我知道使用Thread-safety编写它们并不困难).

另一方面,EJB容器不创建EJB的线程,而是仅重用EJB对象(使用池).由于EJB实例没有多个线程,因此不存在线程安全问题.

我的问题:为什么有不同的行为?将EJB作为Servlet(线程不安全)工作不是一个好主意吗?

我确定我错过了一些东西,并希望了解那个缺失的部分.

JB *_*zet 8

可能是因为它们的设计并没有考虑到相同的目标.

servlet API是一个简单的API,非常接近HTTP协议,您可以在其上构建应用程序或框架.HTTP协议是完全无状态的,我想有必要构建一个无状态的API.在servlet API(例如Stripes)之上构建的几个框架在每个请求中使用一个Action实例,它不会同时使用.

EJB是一个更复杂和更高级别的框架,旨在尽可能简单地实现事务性业务逻辑.它更重量级,并且具有有状态的组件.这些显然需要是线程安全的.我想因为无状态bean也是自然的线程安全.

应该注意的是,例如,Spring bean默认是单例,因此必须遵循与servlet相同的规则.因此,多种设计可以提供或多或少相同的功能.

线程与性能优化无关.如果需要同时处理3个请求,则需要3个线程,无论请求是发送到servlet还是发送到EJB.

  • Servlet和EJB都可以开始/提交事务,从Java EE 6开始,它们都可以是多线程的.实际上,EJB专家组的决策比Servlet专家组更为保守 - 直到最近几年.在EJB 3.2中,我们完全摆脱了那种虚假的"不能使用文件"的限制,这种限制从来不应该只是一个推荐,而应该是EE规范而不是EJB规范. (2认同)
  • 首先,无状态bean可以拥有状态.他们不能有会话状态,这是非常不同的.其次,正如David Blevins在他的回答中解释的那样,你可以使用类似于servlet的单例.第三,在EJB和servlet中使用线程来处理并发请求.唯一的区别是所有并发线程都使用单个servlet实例,而EJB一次只能由一个线程使用.为什么让你觉得创建一个bean实例是如此昂贵?例如,用Java创建对象比执行SQL查询快许多个数量级. (2认同)

Dav*_*ins 8

对你的问题最简单的回答当然是让一个EJB像Servlet一样工作是个好主意,在EJB 3.1中我们添加了一个可以做到这一点的组件: @Singleton

@Singleton豆可以是多线程的像小服务程序,有两种方法:

  • 运用 @ConcurrencyManagement(BEAN)
  • 使用@ConcurrencyManagement(CONTAINER)以及@Lock(READ)在哪里并发所需的方法和@Lock(WRITE)上不是线程安全的方法.

Servlet多年来从未有过的另一件事是<load-on-startup>,它允许Servlet急切加载并在应用程序启动时工作.

为了匹配Servlet,<load-on-start>我们添加了@Startup可以添加到任何@SingletonEJB 的注释,并使其在应用程序启动时启动.这些bean将@PostConstruct在应用程序启动时调用其方法,并@PreDestroy在应用程序关闭时调用它们.

您可以使用数字(<load-on-startup>1</load-on-startup>)来指示使用@Startupstart注释bean 的顺序,而不是使用注释Bean来@DependsOn指定bean,并指定需要在注释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中,在war中打包的EJB将具有与java:comp/envwebapp中所有其他Servlet和EJB 相同的模块范围命名空间,这与EJB在java:comp/envEAR中打包时获得的bean范围命名空间形成鲜明对比.在战争之外.我们对这个问题进行了数周辩论.

很好的一点点啤酒时间琐碎,以测试你的朋友.