java 非托管线程 Spring Quartz Websphere Hibernate
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/175880/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unmanaged Threads Spring Quartz Websphere Hibernate
提问by boyd4715
It appears that our implementation of using Quartz - JDBCJobStore along with Spring, Hibernate and Websphere is throwing unmanaged threads.
看来我们使用 Quartz - JDBCJobStore 以及 Spring、Hibernate 和 Websphere 的实现正在抛出非托管线程。
I have done some reading and found a tech article from IBM stating that the usage of Quartz with Spring will cause that. They make the suggestion of using CommnonJ to address this issue.
我读了一些书,发现 IBM 的一篇技术文章指出 Quartz 与 Spring 的使用会导致这种情况。他们建议使用 CommnonJ 来解决这个问题。
I have done some further research and the only examples I have seen so far all deal with the plan old JobStore that is not in a database.
我做了一些进一步的研究,到目前为止我看到的唯一例子都是处理不在数据库中的旧 JobStore 计划。
So, I was wondering if anyone has an example of the solution for this issue.
所以,我想知道是否有人有这个问题的解决方案的例子。
Thanks
谢谢
回答by Robin
We have a working solution for this (two actually).
我们有一个可行的解决方案(实际上有两个)。
1) Alter the quartz source code to use a WorkManager daemon thread for the main scheduler thread. It works, but requires changing quarts. We didn't use this though since we didn't want maintain a hacked version of quartz. (That reminds me, I was going to submit this to the project but completely forgot)
1)修改quartz源代码,为主调度线程使用WorkManager守护线程。它有效,但需要更换夸脱。但是我们没有使用它,因为我们不想维护石英的黑客版本。(这让我想起了,我正要提交给项目,但完全忘记了)
2) Create a WorkManagerThreadPool to be used as the quartz threadpool. Implement the interface for the quartz ThreadPool, so that each task that is triggered within quartz is wrapped in a commonj Work object that will then be scheduled in the WorkManager. The key is that the WorkManager in the WorkManagerThreadPool has to be initialized before the scheduler is started, from a Java EE thread (such as servlet initialization). The WorkManagerThreadPool must then create a daemon thread which will handle all the scheduled tasks by creating and scheduling the new Work objects. This way, the scheduler (on its own thread) is passing the tasks to a managed thread (the Work daemon).
2) 创建一个 WorkManagerThreadPool 用作石英线程池。实现quartz ThreadPool 的接口,让quartz 内触发的每一个任务都封装在一个commonj Work 对象中,然后在WorkManager 中进行调度。关键是 WorkManagerThreadPool 中的 WorkManager 必须在调度程序启动之前从 Java EE 线程(例如 servlet 初始化)进行初始化。WorkManagerThreadPool 然后必须创建一个守护线程,它将通过创建和调度新的 Work 对象来处理所有调度的任务。这样,调度程序(在其自己的线程上)将任务传递给托管线程(工作守护进程)。
Not simple, and unfortunately I do not have code readily available to include.
不简单,不幸的是我没有现成的代码可以包含。
回答by PaoloC
Adding another answer to the thread, since i found a solution for this, finally.
为该线程添加另一个答案,因为我终于找到了解决方案。
My environment: WAS 8.5.5, Quartz 1.8.5, no Spring.
我的环境:WAS 8.5.5,Quartz 1.8.5,没有 Spring。
The problemi had was the (above stated) unmanaged thread causing a NamingException from ctx.lookup(myJndiUrl), that was instead correctly working in other application servers (JBoss, Weblogic); actually, Webpshere was firing an "incident" with the following message:
我遇到的问题是(上述)非托管线程导致来自 的 NamingException ctx.lookup(myJndiUrl),而在其他应用程序服务器(JBoss、Weblogic)中却正常工作;实际上,Webpshere 正在触发一个带有以下消息的“事件”:
javax.naming.ConfigurationException: A JNDI operation on a "java:" name cannot be completed because the server runtime is not able to associate the operation's thread with any J2EE application component. This condition can occur when the JNDI client using the "java:" name is not executed on the thread of a server application request. Make sure that a J2EE application does not execute JNDI operations on "java:" names within static code blocks or in threads created by that J2EE application. Such code does not necessarily run on the thread of a server application request and therefore is not supported by JNDI operations on "java:" names.
javax.naming.ConfigurationException:无法完成对“java:”名称的 JNDI 操作,因为服务器运行时无法将操作的线程与任何 J2EE 应用程序组件相关联。当使用“java:”名称的 JNDI 客户端未在服务器应用程序请求的线程上执行时,可能会发生这种情况。确保 J2EE 应用程序不会对静态代码块内或由该 J2EE 应用程序创建的线程中的“java:”名称执行 JNDI 操作。此类代码不一定在服务器应用程序请求的线程上运行,因此不受“java:”名称上的 JNDI 操作支持。
The following steps solved the problem:
以下步骤解决了问题:
1)upgraded to quartz 1.8.6 (no code changes), just maven pom
1)升级到quartz 1.8.6(无代码更改),只是maven pom
2)added the following dep to classpath (in my case, EAR's /lib folder), to make the new WorkManagerThreadExecutor available
2)将以下 dep 添加到类路径(在我的情况下,EAR 的 /lib 文件夹),以使新的 WorkManagerThreadExecutor 可用
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-commonj</artifactId>
<version>1.8.6</version>
</dependency>
Note: in QTZ-113or the official Quartz Documentation 1.x2.xthere's no mention on how to activate this fix.
注意:在QTZ-113或官方 Quartz 文档1.x 2.x中没有提及如何激活此修复程序。
3)added the following to quartz.properties ("wm/default" was the JNDI of the already configured DefaultWorkManager in my WAS 8.5.5, see Resources -> AsynchronousBeans -> WorkManagersin WAS console):
3)在quartz.properties 中添加了以下内容(“wm/default”是在我的WAS 8.5.5 中已经配置好的DefaultWorkManager 的JNDI,参见Resources -> AsynchronousBeans -> WorkManagersin WAS console):
org.quartz.threadExecutor.class=org.quartz.custom.WorkManagerThreadExecutor
org.quartz.threadExecutor.workManagerName=wm/default
Note: right class is org.quartz.custom.WorkManagerThreadExecutorfor quartz-scheduler-1.8.6 (tested), or org.quartz.commonj.WorkManagerThreadExecutorfrom 2.1.1on (not tested, but verified within actual quartz-commonj's jarson maven's repos)
注意:右边的类是org.quartz。自定义.WorkManagerThreadExecutor用于quartz-scheduler-1.8.6(已测试)或org.quartz。commonj.WorkManagerThreadExecutor从2.1.1开始(未测试,但在 maven 的 repos 上的实际quartz-commonj jar 中进行了验证)
4)moved the JNDI lookup in the empty constructor of the quartz job(thanks to m_klovre's "Thread outside of the J2EE container"); that is, the constructor was being invoked by reflection (newInstance()method) from the very same J2EE context of my application, and had access to java:globalnamespace, while the execute(JobExecutionContext)method was still running in a poorer context, which was missing all of my application's EJBs
4)在quartz 作业的空构造函数中移动JNDI 查找(感谢m_klovre 的“J2EE 容器之外的线程”);也就是说,构造函数被反射(newInstance()方法)从我的应用程序的完全相同的 J2EE 上下文中调用,并且可以访问java:global命名空间,而该execute(JobExecutionContext)方法仍在较差的上下文中运行,该上下文缺少我的应用程序的所有 EJB
Hope this helps.
希望这可以帮助。
Ps. as a reference, you can find herean example of the quartz.properties file I was using above
附言。作为参考,您可以在此处找到我在上面使用的quartz.properties 文件的示例
回答by PaoloC
Check this article: http://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html
查看这篇文章:http: //www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html
basically, set the taskExecutor property on SchedulerFactoryBean to use a org.springframework.scheduling.commonj.WorkManager TaskExecutor which will use container managed threads.
基本上,在 SchedulerFactoryBean 上设置 taskExecutor 属性以使用 org.springframework.scheduling.commonj.WorkManager TaskExecutor,它将使用容器管理的线程。
回答by PaoloC
Just a note: the above QUARTZ-708's link is not valid anymore. This new issue (in a new Jira) seemsto be addressing the problem: http://jira.terracotta.org/jira/browse/QTZ-113(fixVersion = 1.8.6, 2.0.2)
请注意:上述 QUARTZ-708 的链接不再有效。这个新问题(在新的 Jira 中)似乎正在解决这个问题:http://jira.terracotta.org/jira/browse/QTZ-113 (fixVersion = 1.8.6, 2.0.2)
回答by user2607328
The proposal from PaoloC for WAS85 ans Quartz 1.8.6 also works on WAS80 (and Quartz 1.8.6) and does not need Spring. (In my setup Spring 2.5.5 is present, but not in use in that context.)
PaoloC 针对 WAS85 和 Quartz 1.8.6 的提议也适用于 WAS80(和 Quartz 1.8.6)并且不需要 Spring。(在我的设置中存在 Spring 2.5.5,但在该上下文中未使用。)
That way I was able to override SimpleJobFactory by my own variant, using an InjectionHelper to apply CDI on every newly created job. Injection works for both @EJB (with JNDI lookup of the annotated EJB remote business interface) and @Inject (with JNDI lookup of the CDI BeanManager using a new InitialContext first, and then using this newly fetched BM to lookup the CDI bean itself).
这样我就可以通过我自己的变体覆盖 SimpleJobFactory,使用 InjectionHelper 在每个新创建的作业上应用 CDI。注入适用于@EJB(使用带注释的 EJB 远程业务接口的 JNDI 查找)和 @Inject(使用新的 InitialContext 对 CDI BeanManager 的 JNDI 查找,然后使用这个新获取的 BM 查找 CDI bean 本身)。
Thank you PaoloC for that answer! (I hope this text will appear as an "answer to PaoloC" and not as an answer to the main topic. Found no way to differentiate between these.)
谢谢 PaoloC 的回答!(我希望这篇文章将作为“对 PaoloC 的回答”而不是对主要话题的回答。找不到区分这些的方法。)
回答by pufface
I have recently encountered this problem. Practically you need:
我最近遇到了这个问题。实际上你需要:
- Implement thread pool by delegating work to Websphere Work Manager. (Quartz provides only SimpleThreadPool that run jobs on unmanaged threads). Tell quartz to use this thread pool by
org.quartz.threadPool.classproperty - Tell quartz to use
WorkManagerThreadExecutor(or implement custom one) byorg.quartz.threadExecutor.classproperty - A bit patience with cumbersome legacy web containers :)
- 通过将工作委托给 Websphere Work Manager 来实现线程池。(Quartz 仅提供在非托管线程上运行作业的 SimpleThreadPool)。通过
org.quartz.threadPool.class属性告诉石英使用这个线程池 WorkManagerThreadExecutor通过org.quartz.threadExecutor.class属性告诉石英使用(或实现自定义)- 对繁琐的遗留 Web 容器有点耐心:)
Here is github demoof using Quartz with Websphere (and also Tomcat).
这是在 Websphere(以及 Tomcat)中使用 Quartz 的github 演示。
Hope it helps someone..
希望它可以帮助某人..
回答by pufface
You can check the below JIRA link raised on quartz regarding this.
您可以查看以下有关石英的 JIRA 链接。
http://jira.opensymphony.com/browse/QUARTZ-708
http://jira.opensymphony.com/browse/QUARTZ-708
This has the required WebSphereThreadPool implementation which can be used with the changes in quartz.properties as mentioned to meet your requirements. Hope this helps.
这具有所需的 WebSphereThreadPool 实现,可与上述的quartz.properties 中的更改一起使用以满足您的要求。希望这可以帮助。
Regards, Siva
问候, 西瓦
回答by user355543
You will have to use websphere's managed thread pools. You can do this via spring and commonj. CommonJ can has a task executor that will create managed threads. You can even use a reference to a jndi managed thread resource. You can then inject the commonj task executor into the Spring based Quartz SchedulerFactoryBean.
您将不得不使用 websphere 的托管线程池。你可以通过 spring 和 commonj 来做到这一点。CommonJ 可以有一个任务执行器来创建托管线程。您甚至可以使用对 jndi 托管线程资源的引用。然后,您可以将 commonj 任务执行程序注入基于 Spring 的 Quartz SchedulerFactoryBean。
Please see http://open.bekk.no/boss/spring-scheduling-in-websphere/and scroll to "Quartz with CommonJ" section for more details.
请参阅http://open.bekk.no/boss/spring-scheduling-in-websphere/并滚动到“Quartz with CommonJ”部分了解更多详细信息。

