Java-定時任務


一、 使用 while(true) 和 sleep 實現

new Thread(){
    @Override
    public void run() {
        while (true) {
            System.out.println("Hello!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}.start();

 

二、使用 Timer 和 TimerTask 實現

/**
 * 一個 Timer 對應一個線程,用於執行任務
 * @param name 線程名字
 * @param isDaemon 是否為當前線程的守護線程
 */
Timer timer = new Timer("haha", false);

// 一個 TimerTask 對應一個任務
TimerTask task1 = new TimerTask() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "Hello! A");
    }
};
// 立即執行,只執行一次
timer.schedule(task1, 0);
timer.schedule(task1, 0, 1000);

TimerTask task2 = new TimerTask() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "Hello! B");
    }
};
// 立即執行,然后每秒執行一次
timer.scheduleAtFixedRate(task2, 0, 1000);

Thread.sleep(5000);
// 取消任務
task2.cancel();

Thread.sleep(5000);
// 將所有已經取消的任務移除(釋放資源)
timer.purge();
// 停止 timer 中的所有任務,並終止計時器,無法再提交任務
timer.cancel();

schedule 與 scheduleAtFixedRate 區別

schedule 注重間隔時間,不管任務執行需要多長時間,下一次執行都是在執行完成后的指定間隔時間再執行。

scheduleAtFixedRate 注重執行次數,例如當任務太多或其他原因導致某段時間內執行次數不夠(總時間/間隔時間),則會嘗試縮短間隔時間,保證總體執行次數。

 

三、使用 ScheduledThreadPoolExecutor 實現

阿里巴巴 Java 手冊中的片段

多線程並行處理定時任務時,Timer 運行多個 TimeTask 時,只要其中之一沒有捕獲拋出的異常,其它任務便會自動終止運行,使用 ScheduledExecutorService 則沒有這個問題。

線程池不允許使用 Executors 去創建,而是通過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。
說明:Executors 返回的線程池對象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool:
允許的請求隊列長度為 Integer.MAX_VALUE,可能會堆積大量的請求,從而導致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允許的創建線程數量為 Integer.MAX_VALUE,可能會創建大量的線程,從而導致 OOM。

說明了創建線程池的規范,以及使用 Timer 的問題

// Guava 庫的工具類,線程工廠,這里主要用來設置線程名字
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(10, namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

// 一秒后執行
stpe.schedule(() -> { System.out.println(Thread.currentThread().getName() + "\tA"); }, 1, TimeUnit.SECONDS);
// 立即執行,然后每秒執行一次,注重次數
stpe.scheduleAtFixedRate(() -> { System.out.println(Thread.currentThread().getName() + "\tB"); }, 0, 1, TimeUnit.SECONDS);
// 立即執行,然后每兩秒執行一次,注重間隔時間
stpe.scheduleWithFixedDelay(() -> { System.out.println(Thread.currentThread().getName() + "\tC"); }, 0, 2, TimeUnit.SECONDS);

Thread.sleep(10000);
stpe.purge();
// 關閉
stpe.shutdown();

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM