天天看點

Java ScheduledThreadPoolExecutor延遲或周期性執行任務

Java提供的Time類可以周期性地或者延期執行任務,但是有時我們需要并行執行同樣的任務,這個時候如果建立多個Time對象會給系統帶來負擔,解決辦法是将定時任務放到線程池中執行。

Java的ScheduledThreadPoolExecutor類實作了ScheduledExecutorService接口中定義的以不同方法執行任務的方法。

之前,我寫過一篇關于Java ThreadPoolExecutor的文章中使用了Executors建立線程池。Executors類也提供了工廠方法建立ScheduledThreadPoolExecutor,并且可以設定線程池中的線程。

假設有下面簡單的Runnable類

WorkerThread.java:

<col>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

​<code>​package​</code>​​<code>​com.journaldev.threads;​</code>​

​<code>​import​</code>​​<code>​java.util.Date;​</code>​

​<code>​public​</code>​​<code>​class​</code>​​<code>​WorkerThread ​</code>​​<code>​implements​</code>​​<code>​Runnable{​</code>​

​<code>​private​</code>​​<code>​String command;​</code>​

​<code>​public​</code>​​<code>​WorkerThread(String s){​</code>​

​<code>​this​</code>​​<code>​.command=s;​</code>​

​<code>​}​</code>​

​<code>​@Override​</code>​

​<code>​public​</code>​​<code>​void​</code>​​<code>​run() {​</code>​

​<code>​System.out.println(Thread.currentThread().getName()+​</code>​​<code>​" Start. Time = "​</code>​​<code>​+​</code>​​<code>​new​</code>​​<code>​Date());​</code>​

​<code>​processCommand();​</code>​

​<code>​System.out.println(Thread.currentThread().getName()+​</code>​​<code>​" End. Time = "​</code>​​<code>​+​</code>​​<code>​new​</code>​​<code>​Date());​</code>​

​<code>​private​</code>​​<code>​void​</code>​​<code>​processCommand() {​</code>​

​<code>​try​</code>​​<code>​{​</code>​

​<code>​Thread.sleep(​</code>​​<code>​5000​</code>​​<code>​);​</code>​

​<code>​}​</code>​​<code>​catch​</code>​​<code>​(InterruptedException e) {​</code>​

​<code>​e.printStackTrace();​</code>​

​<code>​public​</code>​​<code>​String toString(){​</code>​

​<code>​return​</code>​​<code>​this​</code>​​<code>​.command;​</code>​

下面的例子中worker線程将被延期10s執行上面的Rnnable類大約花費5s執行任務

ScheduledThreadPool.java:

​<code>​import​</code>​​<code>​java.util.concurrent.Executors;​</code>​

​<code>​import​</code>​​<code>​java.util.concurrent.ScheduledExecutorService;​</code>​

​<code>​import​</code>​​<code>​java.util.concurrent.TimeUnit;​</code>​

​<code>​public​</code>​​<code>​class​</code>​​<code>​ScheduledThreadPool {​</code>​

​<code>​public​</code>​​<code>​static​</code>​​<code>​void​</code>​ ​<code>​main(String[] args) ​</code>​​<code>​throws​</code>​​<code>​InterruptedException {​</code>​

​<code>​ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(​</code>​​<code>​5​</code>​​<code>​);​</code>​

​<code>​//schedule to run after sometime​</code>​

​<code>​System.out.println(​</code>​​<code>​"Current Time = "​</code>​​<code>​+​</code>​​<code>​new​</code>​​<code>​Date());​</code>​

​<code>​for​</code>​​<code>​(​</code>​​<code>​int​</code>​​<code>​i=​</code>​​<code>​0​</code>​​<code>​; i&lt;​</code>​​<code>​3​</code>​​<code>​; i++){​</code>​

​<code>​Thread.sleep(​</code>​​<code>​1000​</code>​​<code>​);​</code>​

​<code>​WorkerThread worker = ​</code>​​<code>​new​</code>​​<code>​WorkerThread(​</code>​​<code>​"do heavy processing"​</code>​​<code>​);​</code>​

​<code>​scheduledThreadPool.schedule(worker,​</code>​​<code>​10​</code>​​<code>​, TimeUnit.SECONDS);​</code>​

​<code>​//add some delay to let some threads spawn by scheduler​</code>​

​<code>​Thread.sleep(​</code>​​<code>​30000​</code>​​<code>​);​</code>​

​<code>​scheduledThreadPool.shutdown();​</code>​

​<code>​while​</code>​​<code>​(!scheduledThreadPool.isTerminated()){​</code>​

​<code>​//wait for all tasks to finish​</code>​

​<code>​System.out.println(​</code>​​<code>​"Finished all threads"​</code>​​<code>​);​</code>​

運作上面的程式,可以得到下面的輸出,由此可以确認任務在10s後才執行。

​<code>​Current Time = Tue Oct 29 15:10:03 IST 2013​</code>​

​<code>​pool-1-thread-1 Start. Time = Tue Oct 29 15:10:14 IST 2013​</code>​

​<code>​pool-1-thread-2 Start. Time = Tue Oct 29 15:10:15 IST 2013​</code>​

​<code>​pool-1-thread-3 Start. Time = Tue Oct 29 15:10:16 IST 2013​</code>​

​<code>​pool-1-thread-1 End. Time = Tue Oct 29 15:10:19 IST 2013​</code>​

​<code>​pool-1-thread-2 End. Time = Tue Oct 29 15:10:20 IST 2013​</code>​

​<code>​pool-1-thread-3 End. Time = Tue Oct 29 15:10:21 IST 2013​</code>​

​<code>​Finished all threads​</code>​

注意到所有的schedule方法都傳回了ScheduledFuture執行個體,可以用于擷取線程狀态資訊和延遲時間。ScheduledFuture接口繼承Future接口,更多資訊見Java Callable Future Example.

在ScheduledExecutorService中至少有2個方法可用于周期性執行任務。

scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)

我們可以使用該方法延遲執行任務,設定任務的執行周期。時間周期從線程池中首先開始執行的線程算起,是以假設period為1s,線程執行了5s,那麼下一個線程在第一個線程運作完後會很快被執行。

比如下面的代碼

​<code>​for​</code>​​<code>​(​</code>​​<code>​int​</code>​​<code>​i = ​</code>​​<code>​0​</code>​​<code>​; i &lt; ​</code>​​<code>​3​</code>​​<code>​; i++) {​</code>​

​<code>​// schedule task to execute at fixed rate​</code>​

​<code>​scheduledThreadPool.scheduleAtFixedRate(worker,​</code>​​<code>​0​</code>​​<code>​,​</code>​​<code>​10​</code>​​<code>​,​</code>​

​<code>​TimeUnit.SECONDS);​</code>​

輸出

​<code>​Current Time = Tue Oct 29 16:10:00 IST 2013​</code>​

​<code>​pool-1-thread-1 Start. Time = Tue Oct 29 16:10:01 IST 2013​</code>​

​<code>​pool-1-thread-2 Start. Time = Tue Oct 29 16:10:02 IST 2013​</code>​

​<code>​pool-1-thread-3 Start. Time = Tue Oct 29 16:10:03 IST 2013​</code>​

​<code>​pool-1-thread-1 End. Time = Tue Oct 29 16:10:06 IST 2013​</code>​

​<code>​pool-1-thread-2 End. Time = Tue Oct 29 16:10:07 IST 2013​</code>​

​<code>​pool-1-thread-3 End. Time = Tue Oct 29 16:10:08 IST 2013​</code>​

​<code>​pool-1-thread-1 Start. Time = Tue Oct 29 16:10:11 IST 2013​</code>​

​<code>​pool-1-thread-4 Start. Time = Tue Oct 29 16:10:12 IST 2013​</code>​

scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)

該方法可被用于延遲周期性執行任務,delaytime是線程停止執行到下一次開始執行之間的延遲時間,假設有下面的代碼

​<code>​scheduledThreadPool.scheduleWithFixedDelay(worker,​</code>​​<code>​0​</code>​​<code>​,​</code>​​<code>​1​</code>​​<code>​,​</code>​

輸出結果

​<code>​Current Time = Tue Oct 29 16:14:13 IST 2013​</code>​

​<code>​pool-1-thread-1 Start. Time = Tue Oct 29 16:14:14 IST 2013​</code>​

​<code>​pool-1-thread-2 Start. Time = Tue Oct 29 16:14:15 IST 2013​</code>​

​<code>​pool-1-thread-3 Start. Time = Tue Oct 29 16:14:16 IST 2013​</code>​

​<code>​pool-1-thread-1 End. Time = Tue Oct 29 16:14:19 IST 2013​</code>​

​<code>​pool-1-thread-2 End. Time = Tue Oct 29 16:14:20 IST 2013​</code>​

​<code>​pool-1-thread-1 Start. Time = Tue Oct 29 16:14:20 IST 2013​</code>​

​<code>​pool-1-thread-3 End. Time = Tue Oct 29 16:14:21 IST 2013​</code>​

​<code>​pool-1-thread-4 Start. Time = Tue Oct 29 16:14:21 IST 2013​</code>​