Timer和TimerTask是用于在后臺線程中調度任務的java util類。簡單地說,TimerTask是要執行的任務,Timer是調度器。
讓我們從簡單地在定時器的幫助下運行單個任務開始:
@Testpublic void givenUsingTimer_whenSchedulingTaskOnce_thenCorrect() { TimerTask task = new TimerTask() { public void run() { System.out.println("Task performed on: " + new Date() + "n" + "Thread's name: " + Thread.currentThread().getName()); } }; Timer timer = new Timer("Timer"); long delay = 1000L; timer.schedule(task, delay);}
延遲時間作為schedule()方法的第二個參數給出。我們將在下一節中了解如何在給定的日期和時間執行任務。
注意,如果我們正在運行這是一個JUnit測試,我們應該添加一個Thread.sleep(delay*2)調用,以允許定時器的線程在JUnit測試停止執行之前運行任務。
現在,讓我們看看Timer#schedule(TimerTask,Date)方法,它將日期而不是long作為其第二個參數,這實現了在某個時刻而不是在延遲之后執行任務。
這一次,讓我們假設我們有一個舊的遺留數據庫,我們希望將它的數據遷移到一個具有更好模式的新數據庫中。我們可以創建一個DatabasemigrationTask類來處理該遷移:
public class DatabaseMigrationTask extends TimerTask { private List<String> oldDatabase; private List<String> newDatabase; public DatabaseMigrationTask(List<String> oldDatabase, List<String> newDatabase) { this.oldDatabase = oldDatabase; this.newDatabase = newDatabase; } @Override public void run() { newDatabase.addAll(oldDatabase); }}
為簡單起見,我們用字符串列表來表示這兩個數據庫。簡單地說,我們的遷移就是將第一個列表中的數據放到第二個列表中。要在所需的時刻執行此遷移,我們必須使用schedule()方法的重載版本:
List<String> oldDatabase = Arrays.asList("Harrison Ford", "Carrie Fisher", "Mark Hamill");List<String> newDatabase = new ArrayList<>();LocalDateTime twoSecondsLater = LocalDateTime.now().plusSeconds(2);Date twoSecondsLaterAsDate = Date.from(twoSecondsLater.atZone(ZoneId.systemDefault()).toInstant());new Timer().schedule(new DatabaseMigrationTask(oldDatabase, newDatabase), twoSecondsLaterAsDate);
我們將遷移任務和執行日期賦予schedule()方法。然后,在twoSecondsLater指示的時間執行遷移:
while (LocalDateTime.now().isBefore(twoSecondsLater)) { assertThat(newDatabase).isEmpty(); Thread.sleep(500);}assertThat(newDatabase).containsExactlyElementsOf(oldDatabase);
雖然我們在這一刻之前,遷移并沒有發生。
既然我們已經討論了如何安排任務的單個執行,那么讓我們看看如何處理可重復的任務。同樣,Timer類提供了多種可能性:我們可以將重復設置為觀察固定延遲或固定頻率。
關于這兩種調度方式,讓我們看看如何使用它們:
為了使用固定延遲調度,schedule()方法還有兩個重載,每個重載都使用一個額外的參數來表示以毫秒為單位的周期性。為什么兩次重載?因為仍然有可能在某個時刻或某個延遲之后開始執行任務。
至于固定頻率調度,我們有兩個scheduleAtFixedRate()方法,它們的周期也是以毫秒為單位的。同樣,我們有一種方法可以在給定的日期和時間啟動任務,還有一種方法可以在給定的延遲后啟動任務。
注意一點:如果一個任務的執行時間超過了執行周期,那么無論我們使用固定延遲還是固定速率,它都會延遲整個執行鏈。
現在,讓我們設想一下,我們要實現一個通訊系統,每周向我們的追隨者發送一封電子郵件。在這種情況下,重復性任務似乎是理想的。所以,讓我們安排每秒鐘的通訊,這基本上是垃圾郵件,但由于發送是假的,所以不用在意:)
讓我們首先設計一個任務:
public class NewsletterTask extends TimerTask { @Override public void run() { System.out.println("Email sent at: " + LocalDateTime.ofInstant(Instant.ofEpochMilli(scheduledExecutionTime()), ZoneId.systemDefault())); }}
每次執行時,任務都會打印其調度時間,我們使用TimerTask#scheduledExecutionTime()方法收集這些時間。那么,如果我們想在固定延遲模式下每秒鐘安排一次這個任務呢?我們必須使用前面提到的schedule()的重載版本:
new Timer().schedule(new NewsletterTask(), 0, 1000);for (int i = 0; i < 3; i++) { Thread.sleep(1000);}
當然,我們只對少數情況進行測試:
Email sent at: 2020-01-01T10:50:30.860 Email sent at: 2020-01-01T10:50:31.860 Email sent at: 2020-01-01T10:50:32.861 Email sent at: 2020-01-01T10:50:33.861
如上所示,每次執行之間至少有一秒鐘的間隔,但有時會延遲一毫秒。這種現象是由于我們決定使用固定延遲重復。
@Testpublic void givenUsingTimer_whenSchedulingDailyTask_thenCorrect() { TimerTask repeatedTask = new TimerTask() { public void run() { System.out.println("Task performed on " + new Date()); } }; Timer timer = new Timer("Timer"); long delay = 1000L; long period = 1000L * 60L * 60L * 24L; timer.scheduleAtFixedRate(repeatedTask, delay, period);}
在run()方法對TimerTask本身的實現中調用TimerTask.cancel()方法:
@Testpublic void givenUsingTimer_whenCancelingTimerTask_thenCorrect() throws InterruptedException { TimerTask task = new TimerTask() { public void run() { System.out.println("Task performed on " + new Date()); cancel(); } }; Timer timer = new Timer("Timer"); timer.scheduleAtFixedRate(task, 1000L, 1000L); Thread.sleep(1000L * 2);}
調用timer.cancel()方法:
@Testpublic void givenUsingTimer_whenCancelingTimer_thenCorrect() throws InterruptedException { TimerTask task = new TimerTask() { public void run() { System.out.println("Task performed on " + new Date()); } }; Timer timer = new Timer("Timer"); timer.scheduleAtFixedRate(task, 1000L, 1000L); Thread.sleep(1000L * 2); timer.cancel(); }
我們也可以使用ExecutorService來安排定時器任務,而不是使用定時器。下面是一個在指定間隔運行重復任務的快速示例:
@Testpublic void givenUsingExecutorService_whenSchedulingRepeatedTask_thenCorrect() throws InterruptedException { TimerTask repeatedTask = new TimerTask() { public void run() { System.out.println("Task performed on " + new Date()); } }; ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); long delay = 1000L; long period = 1000L; executor.scheduleAtFixedRate(repeatedTask, delay, period, TimeUnit.MILLISECONDS); Thread.sleep(delay + period * 3); executor.shutdown();}
那么定時器和ExecutorService解決方案之間的主要區別是什么:
Java定時器樣例代碼
156388.html
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
QQ防沉迷可以改嗎?是的,你可以。1.首先,請登錄您的QQ號碼:2.如果界面在黃色框中顯示“您的身份信息不完整,將被納入防沉迷系統,請盡快填寫您的身份信息”,請盡快點擊藍色橫線上的“添加身份信息”,填寫您的個人信息。3.可以填寫身份證信息,確認信息無誤。5.如需修改,請再次修改身份證信息。6.“你的身份證信息顯示你已滿18周歲,沒有被防沉迷限制,正在等待公安機關核查?!鄙矸葑C輸入后,公安機關會定期...
ps怎么讓皮膚變白?使用軟件版本:PS CS6版本使用Photoshop對人物皮膚進行如下美白:1.打開PS軟件,放入要蒙皮的人的圖像,Ctrl J復制一層;2.執行 amp的設置參數過濾gt雜散gt減少雜散gt先進gt每個頻道在菜單欄中如下:紅色強度10-保留細節100%綠色強度10-保留細節6%藍色強度10-保留細節6%。3.執行命令 "濾鏡gt銳化gtUSM銳化 "在菜單欄中。設置參數個數:...
淘寶上的省錢小助手可靠嗎?你好,我想就這個問題發表我個人的看法]以上是我個人的看法。歡迎大家討論和發表意見無障礙智能助手,可手動開啟。有一個關閉助手要取消淘寶助手,可以在淘寶設置中將其關閉淘寶手機助手是淘寶商家不可或缺的工具之一,但也有很多人反映很難簡單的進入退出。關閉程序后,后臺仍在運行,提示欄中的花仍在。每次都必須關閉背景或強制任務在過程中結束嗎?這是不是太麻煩了?事實上,不是。出現類似情況的...