2011-08-11 44 views
3

我正在编写一个应用程序,它使用MDBs和EJB,并且需要ThreadLocal在事务完成之前跨多个EJB和Helper类传递和记录一个变量。Weblogic线程池中的ThreadLocal安全

的流动

与MDB的onMessage()开始 - >一些企业委托的EJB - >一些助手

问:

这个应用程序内的Weblogic和Weblogic的运行重新使用线程从它的ThreadPool中。那么跨线程的数据损坏是否存在?解决方案是否足够安全地使用ThreadLocal.remove()

除了将对象作为参数传递给所有方法之外,是否还有其他方法可用于ThreadLocal?

回答

5

您无法在EJB层中可靠地使用ThreadLocal。即使你的代码现在看起来“有效”,如果有人远程部署你的一个bean,会发生什么?从EJB Restrictions

为什么线程的创建和管理不允许?

EJB规范为EJB容器分配管理线程的责任 。允许企业bean实例创建并管理线程会干扰容器控制其组件生命周期的能力。线程管理不是业务 函数,它是一个实现细节,通常是复杂的 和平台特定的。让容器管理线程免除了处理线程问题的企业bean开发人员。 多线程应用程序仍然有可能,但多线程控制器 位于容器中,而不是在企业 bean中。

如果您需要共享状态,则应将其作为参数传递给EJB方法。这种方法不适合你吗?另一种选择是暂时将其转储到事务征募数据库或缓存中。

+0

是的,我们的选择是将它作为参数传递。但是这个对象需要遍历超过15个方法调用,所以它会污染我们所有的接口和实现。我们希望保持它非侵入性 - 它实际上是一个记录对象,并由组织强制要求 – JoseK

+1

我不认为你是这样一个人,它似乎是一个很常见的模式。虽然不幸,但面对EJB等组件框架的全部目的,它有点苍白。毕竟,你没有将事务或安全状态传递给每个方法调用,为什么你会传递日志记录状态?也就是说,如果你去参数路由,我会鼓励你把这些信息放在一个更强大的容器中,比如CallingContext对象,然后传递它。然后,当你需要添加下一个伟大的东西(tm)时,你不必重构所有的接口。 –

6

当线程返回池时,WebLogic不重置用户设置的ThreadLocal变量 - 用户负责管理它们。当这些线程被重用时,它们可能会干扰。由于线程本地引用未被清除,因此您可能会遇到内存泄漏。在将线程返回到容器之前,可以安全地重置线程本地。 ThreadLocal.remove()调用应清理它(确保它在finally块中完成)

请注意,如果涉及任何异步或rmi调用,则您的线程本地将不会传播。您可能需要考虑WebLogic WorkArea功能,该功能允许跨线程(客户端&服务器)上下文传播。更多详细信息可在http://download.oracle.com/docs/cd/E17904_01/web.1111/e13706/context.htm#i1058690

0

@JoseK:虽然我还没有尝试过你在你的描述的问题,但这里是我的想法: -

  1. 两个MDB和会话Bean是线程安全的。这意味着让我们说如果有10个豆的池,只有10个请求将被同时处理。其他请求将轮流排队。所以一个正在运行的线程本地数据不应该干扰其他线程。

  2. 如果你确信将来也会使用本地EJB,那么我真的不会在使用线程本地数据时看到任何问题。因为你并没有真正创建线程。

  3. 尽管weblogic提供了线程池中的线程,但该线程专门用于每个请求流,但我认为它的本地数据不会被破坏。

  4. 正如我说我还没有尝试过自己,我会尝试是: -

在MDB层(你的第一层),做Thread.getCurrentThread.setName(名称) 并在随后的图层打印线程名称,如Thread.getCurrentThread.getName)

使用不同大小的ejb池,线程池执行多个运行。为每个请求流提供不同的线程名称。尝试同时运行多个请求。并看看你是否得到混合线程名称。如上所述,为了让事情变得更简单并促进远程EJB支持,我还将CallingContext接口传递给每个层。