据我的理解,Servlet容器创建有限数量的servlet实例并为每个servlet实例创建多个线程以便重复使用这些线程和实例。
由于线程存在多个实例,它们不是“线程安全”的(尽管我知道编写线程安全代码并不困难)。
另一方面,EJB容器不会创建EJB的线程,而是仅重复使用EJB对象(使用池)。由于没有EJB实例的多个线程,因此不存在线程安全问题。
我的问题是:为什么行为不同?将EJB作为Servlet(线程不安全)是否不是一个好主意?
我相信我缺少了什么,并想了解那个缺失之处。
据我的理解,Servlet容器创建有限数量的servlet实例并为每个servlet实例创建多个线程以便重复使用这些线程和实例。
由于线程存在多个实例,它们不是“线程安全”的(尽管我知道编写线程安全代码并不困难)。
另一方面,EJB容器不会创建EJB的线程,而是仅重复使用EJB对象(使用池)。由于没有EJB实例的多个线程,因此不存在线程安全问题。
我的问题是:为什么行为不同?将EJB作为Servlet(线程不安全)是否不是一个好主意?
我相信我缺少了什么,并想了解那个缺失之处。
回答您的问题,当然可以将EJBs像Servlets一样工作,EJB 3.1中增加了一个组件可以实现这一点:@Singleton
@Singleton
bean可以像Servlet一样支持多线程,方法如下:
@ConcurrencyManagement(BEAN)
@ConcurrencyManagement(CONTAINER)
以及@Lock(READ)
,对于不支持线程安全的方法使用@Lock(WRITE)
Servlet有一个多年支持的功能,即<load-on-startup>
允许Servlet在应用程序启动时进行负载和工作。
为了匹配Servlet的<load-on-start>
,我们添加了@Startup
注释,它可以添加到任何@Singleton
EJB中,并在应用程序启动时启动。这些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方法。
java:comp/env
命名空间(根据 EJB 规范,java:comp/env
是 bean-scoped 的)。相比之下,Servlets 从来没有一种方法让单个 Servlet 拥有自己的私有的 java:comp/env
命名空间(根据 Servlet 规范,java:comp/env
是 module-scoped 的)。所以在 EJB 3.1 中,打包在 war 文件中的 EJB 将具有与 Web 应用程序中所有其他 Servlets 和 EJBs 相同的 module-scoped 的 java:comp/env
命名空间,这与打包在 EAR 文件中的 EJB 在其外部拥有 bean-scoped 的 java:comp/env
命名空间形成了很大的对比。我们就这个问题辩论了几个星期。已弃用。自Java Servlet API 2.4版本起不再使用。
public interface SingleThreadModel
确保servlet一次只处理一个请求,该接口没有方法。
如果servlet实现了此接口,则保证在servlet的服务方法中不会并发执行两个线程。Servlet容器可以通过同步访问单个servlet的实例或维护一个servlet实例池并将每个新请求分派到空闲的servlet来保证此功能。
请注意,SingleThreadModel 无法解决所有的线程安全问题。例如,会话属性和静态变量仍然可以被多个请求的多个线程同时访问,即使使用SingleThreadModel servlets也是如此。建议开发人员采用其他方式来解决这些问题,而不是实现此接口,例如避免使用实例变量或同步访问访问这些资源的代码块。此接口在Servlet API版本2.4中已过时。