Weblogic 线程池中的 ThreadLocal 安全
我正在编写一个使用 MDB、EJB 的应用程序,并且需要 ThreadLocal 在多个 EJB 和 Helper 类之间传递和记录变量,直到事务完成。
流程
从 MDB onMessage() 开始 ->一些业务委托 EJB ->一些帮助者
问题:
此应用程序在 Weblogic 中运行,并且 Weblogic 重用其线程池中的线程。那么是否存在跨线程数据损坏的可能性?使用 ThreadLocal.remove() 的解决方案足够安全吗?
除了将对象作为参数传递给所有方法之外,是否还有 ThreadLocal 的替代方案?
I'm writing an app which uses MDBs, EJBs and needs ThreadLocal to pass and log a variable across multiple EJBs and Helper classes until the transaction is complete.
The flow is
Starting with MDB onMessage()
-> some business delegate EJBs
-> some helpers
Question:
This app runs within Weblogic and Weblogic re-uses Threads from within it's ThreadPool. So is there a possibility of data corruption across threads? Is the solution to use ThreadLocal.remove()
safe enough?
Is there an alternative to ThreadLocal other than passing around the Object as a parameter to all methods?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当线程返回池时,WebLogic 不会重置用户设置的 ThreadLocal 变量 - 用户负责管理它们。当重用此类线程时,它们很可能会发生干扰。由于线程本地引用未清理,您可能会遇到内存泄漏。在将线程返回到容器之前,您可以安全地重置线程局部变量。 ThreadLocal.remove() 调用应该清理它(确保它在 finally 块中完成)
请注意,如果涉及任何 async 或 rmi 调用,您的线程局部变量将不会传播。您可能需要考虑 WebLogic WorkArea 功能,该功能允许跨线程、客户端和应用程序进行上下文传播。服务器。更多详细信息,请访问 http://download.oracle.com/docs/cd/E17904_01/web.1111/e13706/context.htm#i1058690
WebLogic does not reset user set ThreadLocal variables when the thread is returned back to the pool - the user is responsible for managing them. When such threads are reused, its likely they will interfere. You may run into memory leaks since the thread local reference isn't cleaned up. You can safely reset your thread locals prior to returning the thread back to the container. The ThreadLocal.remove() call should clean it up (ensure that its done in a finally block)
Note that if any async or rmi calls are involved, your thread locals will not propagate. You may want to consider the WebLogic WorkArea feature which allows context propagation across threads, clients & servers. More details can be found at http://download.oracle.com/docs/cd/E17904_01/web.1111/e13706/context.htm#i1058690
您无法在 EJB 层中可靠地使用 ThreadLocal。即使您的代码现在似乎可以“工作”,但如果有人远程部署您的其中一个 bean,会发生什么情况?来自 EJB 限制:
如果需要共享状态,则应该将其作为参数传递给 EJB 方法。这种方法对您不起作用有什么原因吗?另一种选择是将其临时转储到事务登记数据库或缓存中。
You can't reliably use a ThreadLocal in the EJB tier. Even if your code seems to 'work' now, what happens if someone deploys one of your beans remotely? From EJB Restrictions:
If you need to share state, you should pass it in to the EJB method as a parameter. Is there a reason this approach won't work for you? Another option would be to temporarily dump it into a transaction enlisted database or cache.
@JoseK:虽然我没有尝试过你在问题中描述的内容,但这是我的想法:-
MDB 和会话 bean 都是线程安全的。这意味着如果有 10 个 bean 池,则只会同时处理 10 个请求。其他请求将排队等候。因此,一个正在运行的线程本地数据不应干扰其他线程。
如果您有信心将来也始终使用本地 EJB,那么我确实认为使用线程本地数据没有任何问题。因为你并没有真正创建线程。
虽然 weblogic 提供了来自线程池的线程,但该线程是专门为每个请求流提供的,但我认为它的本地数据不应该被损坏。
正如我所说,我自己没有尝试过,我会尝试的是:-
在 MDB 层(您的第一层)中,执行 Thread .getCurrentThread.setName(名称)
并在后续层中打印线程名称(如 Thread.getCurrentThread.getName)
使用不同大小的 ejb 池、线程池执行多次运行。为每个请求流指定不同的线程名称。尝试同时运行多个请求。看看你是否曾经混淆过线程名称。
5. 如上所述,为了让事情变得更简单并支持未来的远程 EJB,我还将 CallingContext 接口传递给每一层。
@JoseK: though I have not tried what you described in your issue, but here are my thoughts:-
Both MDB and Session beans are thread-safe. It means let us say if there is pool of 10 beans, only 10 requests will be handled simultaneously. Other requests would be queued for their turn. So one running thread local data should not interfere with other thread.
If you confident to use always local EJBs in future also, then I don't really see any issue in using thread local data. Because you are not really creating threads.
Though weblogic provides thread from thread-pool but that thread is given dedicately to each request flow, I don't think its local data should become corrupted ever.
As I said I have not tried myself, what I would try is:-
In MDB layer(your first layer), do Thread.getCurrentThread.setName(name)
and in subsequent layers print thread names like Thread.getCurrentThread.getName)
Perform multiple runs with different size of ejb pool, thread pool. Give a different thread name to each request flow. Try running multiple requests same time. And see if you ever get thread name mixed.
5.Having said above, to keep things simpler and furture remote EJB support, I would also pass CallingContext Interface to each layer.