1. 程式人生 > >Spring的Tomcat服務關閉後,Quartz程序無法正常關閉,出現記憶體洩露

Spring的Tomcat服務關閉後,Quartz程序無法正常關閉,出現記憶體洩露

簡介

  • spring內部整合quartz,將quartz整合到web專案裡面,通過頁面動態控制quartz的增加、修改、刪除、查詢,這種方式極大簡化了對quartz定時器任務的控制;
  • 但隨之而來的是一個極為困擾的問題:當專案的伺服器關閉的時候,quartz定時器任務程序依舊在執行,如果不手動去kill掉程序,這個定時任務會一直殘留,導致下次再重啟伺服器的時候,又重複啟動定時器,導致多個重複的定時任務在執行;
  • 問題展現:
warnning: The web application [xxxxx] 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. Stack trace of thread:
 java.lang.Object.wait(Native Method)
 org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:568)

解決方案

  • 使用監聽器關閉quartz的定時器程序;
  • 在嘗試網上多種解決方案無果之後,從中找到了一些靈感,在關閉tomcat的時候,觸發監聽器,呼叫方法獲取當前程序的所有quartz定時器執行緒,然後強制執行shutdown方法,刪除所有quartz執行緒,雖然非最佳方案,但確實解決了我所頭疼的定時器無法在伺服器關閉的時候自動關閉的問題;
  • 網友解決方案相關連結:
  1. https://blog.csdn.net/only09080229/article/details/42172251
  2. https://www.cnblogs.com/passedbylove/p/7580477.html
  3. https://www.linuxidc.com/Linux/2015-06/119042.htm
  4. https://blog.csdn.net/dslztx/article/details/47276953
  5. https://blog.csdn.net/liujun_for_java/article/details/78101478?utm_source=blogxgwz5

程式碼實踐

  • 首先在web.xml新增監聽器的類對映(如果專案的webapp版本是3.0以上的話可以直接在類上新增@WebListener即可):
  <listener>
    <listener-class>com.sixmonth.common.listener.AppContextListener</listener-class>
  </listener>
  • 建立監聽器java類:
package com.sixmonth.common.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.stereotype.Component;

/**
 * tomcat開啟以及關閉的監聽器
 * @author hqc
 * @Date: 2018年12月13日
 *
 */
@Component
public class AppContextListener implements ServletContextListener{
	
	/**
	 * tomcat啟動初始化
	 */
	@Override
	public void contextInitialized(ServletContextEvent event)  { 
          System.out.println("tomcat已經啟動!");
    }
	
	/**
	 * tomcat關閉
	 */
	@Override
    public void contextDestroyed(ServletContextEvent event)  {
      System.out.println("tomcat已經關閉!開始關閉quartz!");
      try {    
          SchedulerFactory sf = new StdSchedulerFactory();//建立新的排程器工廠
  		  Scheduler scheduler = null;
  		  scheduler = sf.getScheduler();//獲取當前程序的所有定時器執行緒資料
  		  scheduler.shutdown(false);//關閉定時器執行緒
		  
  		  System.out.println("關閉定時器執行緒成功!");
      } catch (Exception e) {
    	  System.out.println("關閉定時器執行緒失敗!");
    	  e.printStackTrace();
      }
    }
}

結語

網上解決此類問題的方法有很多種,有興趣的程式設計師可深入瞭解,如果有更有效的方法歡迎和小編交流,不勝感激~