为啥不鼓励在 Java EE 容器中生成线程?
Posted
技术标签:
【中文标题】为啥不鼓励在 Java EE 容器中生成线程?【英文标题】:Why is spawning threads in Java EE container discouraged?为什么不鼓励在 Java EE 容器中生成线程? 【发布时间】:2010-10-06 17:38:21 【问题描述】:我学到的关于 Java EE 开发的第一件事是,我不应该在 Java EE 容器中生成自己的线程。但细细想来,也不知道是什么原因。
你能清楚地解释为什么不鼓励它吗?
我确信大多数企业应用程序都需要某种异步作业,例如邮件守护程序、空闲会话、清理作业等。
那么,如果确实不应该产生线程,那么在需要时正确的做法是什么?
【问题讨论】:
异步任务通常使用 JMS 消息传递和 MDB 来完成。 一旦在容器中实现JSR 236,这个问题应该很快就会成为过去。 不鼓励这样做,因为任何第二个线程都应该由容器创建和管理,以便线程可以访问其他企业资源。使用 Java EE7,有一种标准且正确的方法可以在企业环境中创建线程。通过使用 Concurrency Utils,您可以确保创建新线程并由容器管理,从而保证所有 EE 服务都可用。示例here JSF/EJB 透视图中的几种正确方法可以在这里找到:***.com/q/6149919 【参考方案1】:不鼓励这样做,因为环境中的所有资源都应由服务器管理,并可能由服务器监控。此外,使用线程的大部分上下文通常附加到执行线程本身。如果您只是启动自己的线程(我相信某些服务器甚至不允许),它就无法访问其他资源。这意味着,您无法获取 InitialContext 并执行 JNDI 查找来访问其他系统资源,例如 JMS 连接工厂和数据源。
有一些方法可以“正确”执行此操作,但这取决于所使用的平台。
The commonj WorkManager is common for WebSphere and WebLogic as well as others
More info here
And here
从今天早上起,this one 也有些重复
更新:请注意,这个问题和答案与 2009 年 Java EE 的状态有关,从那时起情况有所改善!
【讨论】:
您无法获取 InitialContext 并执行 JNDI 查找以访问其他系统资源,例如 JMS 连接工厂和数据源。 我有一个应用程序可以通过在以下情况下注入数据源来解决此问题开始线程,但我可能不得不重新考虑这种方法...... 现在有一种标准且正确的方法可以使用核心 Java EE API 创建线程。通过使用 Concurrency Utils,您可以确保创建新线程并由容器管理,从而保证所有 EE 服务都可用。示例here 和here @ChrisRitchie 感谢您的提示。如果只有 JBoss AS/IBM WAS 支持 Java EE 7... :-( @asgs WildFly 8(JBoss AS 的新名称)确实支持 Java EE 7。IBM 仅通过 Java EE 6 认证certification【参考方案2】:对于 EJB,不仅不鼓励,specification 明确禁止:
企业 bean 不得使用线程 同步原语 同步执行多个 实例。
和
企业 bean 不得尝试 管理线程。企业 bean 不得尝试启动、停止、 暂停或恢复线程,或 更改线程的优先级或名称。 企业 bean 不得尝试 管理线程组。
原因是 EJB 旨在在分布式环境中运行。 EJB 可能从集群中的一台机器移动到另一台机器。线程(以及套接字和其他受限设施)是这种可移植性的重大障碍。
【讨论】:
Java EE7 Concurrency Utils 提供了在企业环境中创建线程的正确方法。示例 here 和 here @Dan 你能向我解释一下为什么线程会严重阻碍将 EJB 从一个集群中的一台机器移动到另一台机器的可移植性吗?【参考方案3】:您不应该生成自己的线程的原因是这些线程不会由容器管理。容器处理了很多新手开发人员难以想象的事情。例如,线程池、集群、崩溃恢复等事情都是由容器执行的。当你开始一个线程时,你可能会丢失其中的一些。此外,容器允许您重新启动应用程序,而不会影响它运行的 JVM。如果有线程超出容器的控制,这怎么可能?
这就是从 J2EE 1.4 开始引入定时器服务的原因。详情见this文章。
【讨论】:
JSR 236 添加了支持在 Java EE 7 及更高版本中生成线程的功能。见this sibling Answer by Chris Ritchie。【参考方案4】:Java EE 的并发实用程序
现在有一种使用核心 Java EE API 创建线程的标准且正确的方法:
JSR 236: Concurrency Utilities for Java™ EE通过使用 Concurrency Utils,您可以确保创建新线程并由容器管理,从而保证所有 EE 服务都可用。
例子here
【讨论】:
【参考方案5】:没有真正的理由不这样做。我在 web 应用程序中使用 Quarz 和 Spring 没有问题。也可以使用并发框架java.util.concurrent
。如果您实现自己的线程处理,请将 theads 设置为 deamon 或为它们使用自己的守护线程组,以便容器可以随时卸载您的 web 应用程序。
但要小心,bean 范围 session 和 request 在产生的线程中不起作用! ThreadLocal
上的其他代码也不能开箱即用,您需要自己将值传输到生成的线程。
【讨论】:
【参考方案6】:您总是可以告诉容器启动东西作为部署描述符的一部分。然后,它们可以执行您需要执行的任何维护任务。
遵守规则。有一天你会很高兴你做到了:)
【讨论】:
【参考方案7】:根据蓝图,Java EE 容器中禁止使用线程。更多信息请参考blueprints。
【讨论】:
【参考方案8】:我从来没有读过它被劝阻,除了因为它不容易正确地做到这一点。
这是相当低级的编程,与其他低级技术一样,您应该有充分的理由。使用线程池等内置结构可以更有效地解决大多数并发问题。
【讨论】:
规范确实是禁止的。【参考方案9】:我发现了一个原因,如果您在 EJB 中生成一些线程,然后您尝试卸载容器或更新您的 EJB,您将会遇到问题。几乎总是有另一种方法可以做一些你不需要线程的事情,所以说不。
【讨论】:
以上是关于为啥不鼓励在 Java EE 容器中生成线程?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在 Javascript 中不鼓励在 while 语句中赋值?
为啥现代 JavaScript 框架不鼓励与 DOM 直接交互