我在项目中使用石英。我的Web应用程序显然在停止时导致内存泄漏,错误是:
SEVERE: A web application appears to have started a TimerThread named [Timer-12] via the java.util.Timer API but has failed to stop it. To prevent a memory leak, the timer (and hence the associated thread) has been forcibly cancelled.
Jan 2, 2013 6:55:35 AM org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
SEVERE: A web application appears to have started a thread named [DefaultQuartzScheduler_Worker-1] but has failed to stop it. This is very likely to create a memory leak.
我使用了org.quartz.ee.servlet.QuartzInitializerServlet
和org.quartz.ee.servlet.QuartzInitializerListener
。我工厂的代码是:
StdSchedulerFactory factory = (StdSchedulerFactory) context.getAttribute(QuartzInitializerListener.QUARTZ_FACTORY_KEY );
和web.xml中的quartz设置为:
<servlet>
<servlet-name>
QuartzInitializer
</servlet-name>
<display-name>
Quartz Initializer Servlet
</display-name>
<servlet-class>
org.quartz.ee.servlet.QuartzInitializerServlet
</servlet-class>
<load-on-startup>
1
</load-on-startup>
<init-param>
<param-name>shutdown-on-unload</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>wait-on-shutdown</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>start-scheduler-on-load</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<context-param>
<param-name>quartz:shutdown-on-unload</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>quartz:wait-on-shutdown</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>quartz:start-on-load</param-name>
<param-value>true</param-value>
</context-param>
<listener>
<listener-class>
org.quartz.ee.servlet.QuartzInitializerListener
</listener-class>
</listener>
请帮我解决这个内存泄漏!!
答案 0 :(得分:4)
通过实现org.quartz.InterruptableJob
,您可以正确地中断由servlet卸载触发的线程。
@DisallowConcurrentExecution
public class Job implements InterruptableJob {
private Thread thread;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
thread = Thread.currentThread();
// ... do work
}
@Override
public void interrupt() throws UnableToInterruptJobException {
thread.interrupt();
try {
thread.join();
} catch (InterruptedException e) {
throw new UnableToInterruptJobException(e);
} finally {
// ... do cleanup
}
}
}
如果作业在中断之前尚未执行,则此示例可能会导致线程变量出现争用条件错误。我将最终解决方案打开以获取建议,具体取决于目标应用程序的生命周期。如果需要通过同一个作业实例进行并发执行,请扩充解决方案以处理多个线程并删除@DisallowConcurrentExecution
注释。
为了使其工作,石英属性org.quartz.scheduler.interruptJobsOnShutdownWithWait
必须设置为true
。这可以通过为调度程序定义属性文件来完成,或者如果使用spring框架则通过bean引用来完成。
示例quartz.properties
文件:
org.quartz.scheduler.interruptJobsOnShutdownWithWait=true
注意如果调度程序配置为在关机时等待,则仅调度中断,从而调用scheduler.shutdown(true)
。
答案 1 :(得分:2)
我看到你初始化了两个实例...... - 首先通过org.quartz.ee.servlet.QuartzInitializerServlet - 第二个通过org.quartz.ee.servlet.QuartzInitializerListener
删除QuartzInitializerServlet或QuartzInitializerListener(以及相应的参数)...... 如果你想拥有多个实例(出于特定原因),请使用QuartzInitializerServlet(并且不要忘记每个实例使用不同的实例)
答案 2 :(得分:1)
如果您正在为Web应用程序使用自己的ServletContextListener接口实现,则可以在contextDestroyed方法中正常关闭Quartz。请在下面找到Quartz版本2.1.7的示例代码。
你的工作:
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class CronJob implements Job {
public void execute(JobExecutionContext context)
throws JobExecutionException {
// TODO: do you job
}
}
您的工作安排员:
import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
public class CronJobScheduler {
private static CronJobScheduler instance = new CronJobScheduler();
private Scheduler scheduler;
private CronJobScheduler() {
try {
scheduler = new StdSchedulerFactory().getScheduler();
} catch (SchedulerException e) {
// TODO
}
}
public static CronJobScheduler getInstance() {
return instance;
}
public void trigger() {
JobKey jobKey = JobKey.jobKey("myJobName", "myJobGroup");
JobDetail job = JobBuilder.newJob(CronJob.class).withIdentity(jobKey).build();
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("myTriggerName", "myJobGroup")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 1,13 * * ?"))
.build();
try {
scheduler.start();
scheduler.scheduleJob(job, trigger);
} catch (SchedulerException e) {
// TODO
}
}
public void shutdown(boolean waitForJobsToComplete) {
try {
scheduler.shutdown(waitForJobsToComplete);
} catch (SchedulerException e) {
// TODO
}
}
}
您的ServletContextListener接口的实现:
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent arg0) {
CronJobScheduler.getInstance().shutdown(true);
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
CronJobScheduler.getInstance().trigger();
}
}
您的web.xml
<listener>
<listener-class>my.package.name.MyServletContextListener</listener-class>
</listener>
答案 3 :(得分:0)
我想你想要:
<init-param>
<param-name>wait-on-shutdown</param-name>
<param-value>true</param-value>
</init-param>
你有一个“quartz:”前缀,可能导致Quartz恢复为该配置设置的默认值“false”。