我們已經(jīng)學習了如何利用執(zhí)行器框架提供的ThreadPoolExecutor類的線程池來執(zhí)行任務(wù),而不用我們手動去創(chuàng)建線程。同時我們也學習了,如何使用ScheduledThreadPoolExecutor類來延遲執(zhí)行任務(wù),如果你要指定任務(wù)執(zhí)行的時間點,你只需要計算當前時間與目標時間的差值,把這個差值作為延遲時間即可實現(xiàn)定時執(zhí)行任務(wù)。
接下來,如果我們想要周期性地執(zhí)行一個任務(wù),該怎么辦呢。同樣,我們可以使用ScheduledThreadPoolExecutor類來實現(xiàn)這個功能。
首先創(chuàng)建一個任務(wù)類,并實現(xiàn)Runnable接口。在call()方法中打印任務(wù)執(zhí)行時間。
import java.util.Date;
/**
* 新建Task類并實現(xiàn)Runnable接口
*
* 打印當前任務(wù)名+執(zhí)行時間
*
* Created by hadoop on 2016/11/3.
*/
public class Task implements Runnable {
private String name;
public Task(String name) {
this.name = name;
}
@Override
public void run() {
System.out.printf("%s: Starting at : %s\n", name, new Date());
}
}
然后我們創(chuàng)建主線程類。使用Executors工廠類的newScheduledThreadPoolExecutor來創(chuàng)建線程執(zhí)行器,并調(diào)用它的scheduleAtFixedRate方法來周期性地執(zhí)行任務(wù),注意這個周期任務(wù)執(zhí)行方法與schedule()延遲執(zhí)行方法不同的是,它只能接受Runnable對象,并不支持Callable。
/**
* 這個方法有四個參數(shù)
* @command::需要執(zhí)行的任務(wù)
* @initialDelay:第一次執(zhí)行延遲
* @period:執(zhí)行周期
* @TimeUnit:時間單位
*/
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit)
/**
* 在執(zhí)行器中周期性的執(zhí)行任務(wù)
*
* 上一節(jié)我們學習了使用ScheduledThreadPoolExecutor來延遲執(zhí)行任務(wù),這一節(jié)我們需要學如何周期性地執(zhí)行任務(wù)。
*
* 要想周期性的執(zhí)行任務(wù),我們需要調(diào)用scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS)方法。
* 這個方法接受4個參數(shù):
* 第一個實現(xiàn)Runnable接口的任務(wù)實例
* 第二個參數(shù)是第一次執(zhí)行的延遲
* 第三個參數(shù)是兩次執(zhí)行的時間間隔
* 第四個參數(shù)是第二個參數(shù)和第三個參數(shù)的單位
*
* 這個方法返回一個ScheduledFuture<?>類型的對象,我們可以通過這個對象的getDelay()方法來返回任務(wù)到下一次執(zhí)行時所需要等待的時間。
*
* ScheduledThreadPoolExecutor還提供了另外一個方法scheduleWithFixedDelay()。
* 這個方法與scheduleAtFixedRate()方法接收的參數(shù)相同。
* 只不過它的第三個參數(shù)不是兩次執(zhí)行開始的間隔時間,而是上一次任務(wù)執(zhí)行結(jié)束到下次任務(wù)之行開始的間隔時間。
*
* Created by hadoop on 2016/11/3.
*/
public class Main {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor)Executors.newScheduledThreadPool(4);
Task task = new Task("Task");
ScheduledFuture<?> future = executor.scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS);
//ScheduledFuture<String> future = executor.scheduleWithFixedDelay(task, 1, 2, TimeUnit.SECONDS);
for (int i =0; i < 10; i++) {
System.out.printf("Main: Delay: %s. Result: %s\n", future.getDelay(TimeUnit.MILLISECONDS), future.get());
TimeUnit.MILLISECONDS.sleep(1000);
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.DAYS);
}
}
我們每隔一秒鐘打印一次,任務(wù)下次執(zhí)行的時間間隔。其中有一點要說明的是,執(zhí)行器給我們提供了兩個周期任務(wù)執(zhí)行方法。
- scheduleAtFixedDelay():這個方法是從上一個任務(wù)執(zhí)行開始就計算下次任務(wù)執(zhí)行時間。
- scheduleWithFixedDelay():這個方法是從上一個任務(wù)執(zhí)行結(jié)束后才開始計算下次任務(wù)執(zhí)行時間。
另外提一點,當設(shè)置執(zhí)行器方法setContinueExistingPeriodicTasksAfterShutdownPolicy(true)為true的時候,即使關(guān)閉執(zhí)行器,周期任務(wù)也會繼續(xù)執(zhí)行。