首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 實現每日定時任務的完整指南:從 Timer 到最佳實踐

     編輯:Java 相關知識

前言

在 Java 開發中,定時任務是常見需求:如每日清理日誌、定時同步數據、發送報表等。本文將通過一個完整的「每日凌晨 2 點執行」案例,詳細講解如何使用 Timer 和 TimerTask 實現每日定時任務,並重點分析「首次執行時間早於當前時間」導致任務立即執行的經典坑及其解決方案。

核心代碼實現

1. 任務管理器 TimerManager

public class TimerManager {
    // 時間間隔:一天(毫秒)
    private static final long PERIOD_DAY = 24 * 60 * 60 * 1000;

    public TimerManager() {
        Calendar calendar = Calendar.getInstance();

        // 設定每日 2:00 執行
        calendar.set(Calendar.HOUR_OF_DAY, 2);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);

        Date date = calendar.getTime(); // 首次執行時間

        // 關鍵判斷:若首次執行時間早於當前時間,則順延一天
        if (date.before(new Date())) {
            date = this.addDay(date, 1);
        }

        Timer timer = new Timer();
        NFDFlightDataTimerTask task = new NFDFlightDataTimerTask();
        // 安排任務:指定時間開始,固定延遲重複執行
        timer.schedule(task, date, PERIOD_DAY);
    }

    // 輔助方法:增加/減少天數
    public Date addDay(Date date, int num) {
        Calendar startDT = Calendar.getInstance();
        startDT.setTime(date);
        startDT.add(Calendar.DAY_OF_MONTH, num);
        return startDT.getTime();
    }
}

2. 具體任務類 NFDFlightDataTimerTask

public class NFDFlightDataTimerTask extends TimerTask {
    private static Logger log = Logger.getLogger(NFDFlightDataTimerTask.class);

    @Override
    public void run() {
        try {
            // 在此編寫具體業務邏輯
            // 例如:數據同步、報表生成、緩存清理等
        } catch (Exception e) {
            log.info("-------------解析信息發生異常--------------");
        }
    }
}

3. Web 容器啟動監聽器 NFDFlightDataTaskListener

public class NFDFlightDataTaskListener implements ServletContextListener {
    public void contextInitialized(ServletContextEvent event) {
        new TimerManager(); // 應用啟動時啟動定時任務
    }

    public void contextDestroyed(ServletContextEvent event) {
        // 可在此添加銷毀邏輯,如取消 timer
    }
}

4. web.xml 配置監聽器

<listener>
    <listener-class>
        com.listener.NFDFlightDataTaskListener
    </listener-class>
</listener>

關鍵點深度解析:為什麼要判斷 date.before(new Date())?

這是本例中最核心、最容易踩坑的地方。

  • 場景:假設設定每日 02:00 執行,但應用是在 03:00 部署或重啟的。
  • 問題:若無判斷,date(今天 02:00)早於當前時間(今天 03:00),timer.schedule 會認為「首次執行時間已過」,導致任務立即執行一次,而非等待明天 02:00。
  • 解決:代碼中通過 if (date.before(new Date())) date = addDay(date, 1); 將首次執行時間順延至明天 02:00,完美規避此問題。

擴展建議:生產環境的更優選擇

雖然 Timer 簡單易用,但在高併發、長時間運行的生產環境中,建議考慮:

  • ScheduledExecutorService:JDK 1.5+ 提供,基於線程池,異常處理更健壯,支持固定頻率/固定延遲兩種模式。
  • Spring @Scheduled / Quartz:企業級應用首選,支持 Cron 表達式、集群、持久化、動態調度等高級功能。

總結

本文通過完整代碼演示了使用 Timer 實現每日定時任務的標準流程,重點剖析了「首次執行時間校正」這一關鍵邏輯。掌握此機制,能讓你在維護舊項目或輕量級場景下游刃有餘;而在新項目中,請優先擁抱 ScheduledExecutorService 或成熟調度框架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved