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

Java Timer 定時器原理與實戰:從基礎用法到彈跳球動畫與 ScheduledThreadPoolExecutor 替代方案

     編輯:Java 相關知識

Timer 基礎架構

  • Timer:單一後台執行緒,循序執行所有排程任務,線程安全。
  • TimerTask:抽象類,繼承並實作 run() 定義任務邏輯。

常用排程方法

方法說明
schedule(task, time)指定時間執行一次
schedule(task, delay)延遲指定毫秒執行一次
schedule(task, delay, period)延遲後每隔 period 執行(固定延遲)
scheduleAtFixedRate(task, delay, period)延遲後每隔 period 執行(固定頻率)

差異:schedule 以「上次實際執行時間 + period」為下次計劃時間(保間隔);scheduleAtFixedRate 以「首次計劃時間 + n*period」為計劃時間(保頻率),任務超時會並發執行追趕進度。

基礎範例

延遲 3 秒執行

new Timer().schedule(new TimerTask() {
    public void run() { System.out.println("Time's up!"); }
}, 3000);

指定時間執行

Calendar cal = Calendar.getInstance();
cal.set(2025, Calendar.JANUARY, 1, 0, 0, 0);
new Timer().schedule(new TimerTask() { ... }, cal.getTime());

週期性執行

new Timer().schedule(new TimerTask() {
    public void run() { System.out.println("Tick: " + new Date()); }
}, 1000, 2000); // 1秒後開始,每2秒一次

Timer 缺陷

  1. 單執行緒阻塞:某任務耗時過長會延遲後續所有任務。
  2. 異常吞噬:TimerTask 拋出未檢查異常會終結 Timer 執行緒,導致後續任務永不執行。
  3. 依賴系統時間:系統時間修改會影響排程準確性。

替代方案:ScheduledThreadPoolExecutor

基於執行緒池、支援並發、異常隔離、基於絕對時間(NanoTime),JDK 5+ 推薦。

ScheduledExecutorService exec = Executors.newScheduledThreadPool(2);

// 固定延遲
exec.scheduleWithFixedDelay(() -> {
    System.out.println("Task A");
    try { Thread.sleep(4000); } catch (InterruptedException e) {}
}, 1, 2, TimeUnit.SECONDS);

// 固定頻率
exec.scheduleAtFixedRate(() -> System.out.println("Task B"), 2, 1, TimeUnit.SECONDS);

輸出顯示 Task B 不受 Task A 阻塞影響,準時執行。

異常處理對比

// Timer: 任務拋出 RuntimeException -> 整個 Timer 死掉
// ScheduledThreadPoolExecutor: 單任務異常不影響其他任務
exec.schedule(() -> { throw new RuntimeException(); }, 1, TimeUnit.SECONDS);
exec.scheduleAtFixedRate(() -> System.out.println("Still alive"), 2, 1, TimeUnit.SECONDS);

實戰:彈跳球動畫

用 javax.swing.Timer(事件派發執行緒安全)驅動重繪,JSpinner 調整延遲控制速度。

public class BallsCanvas extends JPanel implements ActionListener {
    private final Ball[] balls;
    private final Timer timer;

    public BallsCanvas(Color[] colors, int delay) {
        balls = new Ball[colors.length];
        for (int i = 0; i < colors.length; i++)
            balls[i] = new Ball(40 + i*40, 40 + i*40, colors[i]);
        timer = new Timer(delay, this);
        timer.start();
    }

    public void setDelay(int d) { timer.setDelay(d); }

    @Override protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (Ball b : balls) {
            g.setColor(b.color);
            b.move(getWidth(), getHeight());
            g.fillOval(b.x, b.y, 20, 20);
        }
    }

    @Override public void actionPerformed(ActionEvent e) { repaint(); }

    static class Ball {
        int x, y; Color color; boolean left, up;
        Ball(int x, int y, Color c) { this.x=x; this.y=y; this.color=c; }
        void move(int maxW, int maxH) {
            x += left ? -10 : 10; if (x<0 || x>=maxW) left = !left;
            y += up ? -10 : 10; if (y<0 || y>=maxH) up = !up;
        }
    }
}

總結建議

  • 簡單單次/週期任務 → Timer 夠用。
  • 生產環境、高併發、需異常隔離 → 首選 ScheduledThreadPoolExecutor。
  • Swing GUI 週期性更新 → 用 javax.swing.Timer 保證 EDT 安全。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved