ScheduledExecutorService
前言
??在Java中我們一般使用Timer來進(jìn)行延時(shí)/周期執(zhí)行操作,Timer的內(nèi)部只有一個線程,如果有多個任務(wù)的話就會順序執(zhí)行,這樣我們的延遲時(shí)間和循環(huán)時(shí)間就會出現(xiàn)問題。除此之外:在多線程并發(fā)執(zhí)行定時(shí)操作時(shí),Timer運(yùn)行多個TimerTask,如果其中一個任務(wù)沒有異常沒有捕獲,那所有任務(wù)都將終止。還有就是,Timer是基于絕對時(shí)間,而ScheduledExecutorService是基于相對時(shí)間的,這個看情況而定,一般基于相對時(shí)間更靈活一些。所以作為Timer的替代品,在對延遲任務(wù)和循環(huán)任務(wù)要求嚴(yán)格的時(shí)候,最好使用ScheduledExecutorService。
ScheduledExecutorService提供了三種方法來進(jìn)行延時(shí)/周期操作:schedule、scheduleAtFixedRate、scheduleWithFixedDelay。
schedule方法
ScheduledExecutorService用于延遲一段時(shí)間后執(zhí)行任務(wù)或者周期性的執(zhí)行任務(wù).通常使用Executor類的工廠方法去實(shí)例化一個ScheduledExecutorService是一個比較好的方式。.
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1000);
//延遲兩秒打印fsd,這里使用了lamda表達(dá)式簡化,相當(dāng)于new Runable()
scheduledThreadPool.schedule(() ->System.out.println("fsd"), 2, TimeUnit.SECONDS);
scheduleAtFixedRate方法
scheduleAtFixedRate()方法在延遲一段時(shí)間之后周期性的執(zhí)行一個任務(wù).下面的代碼將會先延遲1秒之后首次執(zhí)行,之后每隔3秒執(zhí)行,不管任務(wù)耗時(shí)多久,3秒后都立即執(zhí)行下一個任務(wù)。
ScheduledExecutorService executorService =Executors.newSingleThreadScheduledExecutor();
//第一次延遲一秒打印,后每三秒打印一次,這里使用了lamda表達(dá)式簡化,相當(dāng)于new Runable()
executorService.scheduleAtFixedRate(() ->System.out.println("fsd"),1,3,TimeUnit.SECONDS);
總結(jié)一下就是:scheduleAtFixedRate是按照上一次任務(wù)的發(fā)起時(shí)間計(jì)算下一次任務(wù)的開始時(shí)間。
scheduleWithFixedDelay方法
如果需要任務(wù)周期性執(zhí)行的時(shí)候保持固定的時(shí)間間隔,應(yīng)該使用scheduleWithFixedDalay()方法.如下的代碼保證上一次任務(wù)執(zhí)行完(不管多久)過10秒之后再執(zhí)行下一次任務(wù).
ScheduledExecutorService executorService =Executors.newSingleThreadScheduledExecutor();
//第一次延遲一秒打印,后每三秒打印一次,這里使用了lamda表達(dá)式簡化,相當(dāng)于new Runable()
executorService.scheduleWithFixedDelay(() ->System.out.println("fsd"),1,3,TimeUnit.SECONDS);
總結(jié)一下就是:.scheduleWithFixedDelay以上一次任務(wù)的結(jié)束時(shí)間計(jì)算下一次任務(wù)的開始時(shí)間
**注意:
如果ExecutorService被關(guān)閉,或者在任務(wù)執(zhí)行過程中拋出了一個異常,那么周期性執(zhí)行的任務(wù)將會終止.。所以最好在Runable中的run方法中捕獲所有異常,保證循環(huán)的進(jìn)行,如下:
public class MyThread implements Runnable{
@Override
public void run() {
try {
int sleepNumber = random.nextInt(3);
if(sleepNumber ==2){
int error = 1/0;
}
} catch (Exception e) {
e.printStackTrace();
}
}