Concurrency continues. The previous Blog did not introduce ScheduledThreadPoolExecutor and said that he would write a Blog with Timer.
1. Defects in Timer's management of delayed tasks
A. In the past, timers were often used in projects. For example, some junk files in the project were cleaned at intervals for data cleaning. However, Timer has some defects, because Timer only creates one thread when executing a scheduled task, if multiple tasks exist and the task takes too long, beyond the interval between the two tasks, some defects will occur: the following is an example:
Timer source code:
public class Timer { /** * The timer task queue. This data structure is shared with the timer * thread. The timer produces tasks, via its various schedule calls, * and the timer thread consumes, executing timer tasks as appropriate, * and removing them from the queue when they're obsolete. */ private TaskQueue queue = new TaskQueue(); /** * The timer thread. */ private TimerThread thread = new TimerThread(queue);
TimerThread is a subclass of Thread. It can be seen that there is only one Thread in it. The following is an example:
package com.zhy.concurrency.timer;import java.util.Timer;import java.util.TimerTask;public class TimerTest{private static long start;public static void main(String[] args) throws Exception{TimerTask task1 = new TimerTask(){@Overridepublic void run(){System.out.println("task1 invoked ! "+ (System.currentTimeMillis() - start));try{Thread.sleep(3000);} catch (InterruptedException e){e.printStackTrace();}}};TimerTask task2 = new TimerTask(){@Overridepublic void run(){System.out.println("task2 invoked ! "+ (System.currentTimeMillis() - start));}};Timer timer = new Timer();start = System.currentTimeMillis();timer.schedule(task1, 1000);timer.schedule(task2, 3000);}}
Two tasks are defined. It is expected that the first task will be executed after 1 S, and the second task will be executed after 3 s, but the running result is as follows:
task1 invoked ! 1000task2 invoked ! 4000
Task 2 is actually executed after 4, because Timer is a thread internally, and the time required by Task 1 exceeds the interval between two tasks. The following uses ScheduledThreadPool to solve this problem:
Package com. zhy. concurrency. timer; import java. util. timerTask; import java. util. concurrent. executors; import java. util. concurrent. scheduledExecutorService; import java. util. concurrent. timeUnit; public class ScheduledThreadPoolExecutorTest {private static long start; public static void main (String [] args) {/*** initialize a ScheduledThreadPool using the factory Method */ScheduledExecutorService newScheduledThreadPool = Executors. new ScheduledThreadPool (2); TimerTask task1 = new TimerTask () {@ Overridepublic void run () {try {System. out. println ("task1 invoked! "+ (System. currentTimeMillis ()-start); Thread. sleep (3000);} catch (Exception e) {e. printStackTrace () ;}}; TimerTask task2 = new TimerTask () {@ Overridepublic void run () {System. out. println ("task2 invoked! "+ (System. currentTimeMillis ()-start) ;}}; start = System. currentTimeMillis (); newScheduledThreadPool. schedule (task1, 1000, TimeUnit. MILLISECONDS); newScheduledThreadPool. schedule (task2, 3000, TimeUnit. MILLISECONDS );}}
Output result:
task1 invoked ! 1001task2 invoked ! 3001
Meets our expected results. Because ScheduledThreadPool is a thread pool, it supports concurrent execution of multiple tasks.
2. Defects of Timer when a task throws an exception
If TimerTask throws RuntimeException, Timer stops running all tasks:
package com.zhy.concurrency.timer;import java.util.Date;import java.util.Timer;import java.util.TimerTask;public class ScheduledThreadPoolDemo01{public static void main(String[] args) throws InterruptedException{final TimerTask task1 = new TimerTask(){@Overridepublic void run(){throw new RuntimeException();}};final TimerTask task2 = new TimerTask(){@Overridepublic void run(){System.out.println("task2 invoked!");}};Timer timer = new Timer();timer.schedule(task1, 100);timer.scheduleAtFixedRate(task2, new Date(), 1000);}}
There are two tasks on the top. Task 1 throws a runtime exception. Task 2 Periodically executes an operation and outputs the following results:
task2 invoked!Exception in thread "Timer-0" java.lang.RuntimeExceptionat com.zhy.concurrency.timer.ScheduledThreadPoolDemo01$1.run(ScheduledThreadPoolDemo01.java:24)at java.util.TimerThread.mainLoop(Timer.java:512)at java.util.TimerThread.run(Timer.java:462)
Task 2 also stops running because of one time of Task 1... The following uses ScheduledExecutorService to solve this problem:
package com.zhy.concurrency.timer;import java.util.Date;import java.util.Timer;import java.util.TimerTask;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;public class ScheduledThreadPoolDemo01{public static void main(String[] args) throws InterruptedException{final TimerTask task1 = new TimerTask(){@Overridepublic void run(){throw new RuntimeException();}};final TimerTask task2 = new TimerTask(){@Overridepublic void run(){System.out.println("task2 invoked!");}};ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);pool.schedule(task1, 100, TimeUnit.MILLISECONDS);pool.scheduleAtFixedRate(task2, 0 , 1000, TimeUnit.MILLISECONDS);}}
The code is basically the same, but ScheduledExecutorService can ensure that task 1 does not affect the running of Task 2 when an exception occurs:
task2 invoked!task2 invoked!task2 invoked!task2 invoked!task2 invoked!...
3. Timer depends on the system time when executing cyclic tasks
Timer depends on the system time when executing a periodic task. If the current system time changes, some execution changes will occur. ScheduledExecutorService is time-based and will not be executed because of system time changes.
As mentioned above, we will try to replace Timer with ScheduledExecutorService (after JDK1.5) in future development.
Okay. If there is an error in the blog, please leave a message to point out ~