Timer与TimerTask之二:timer使用缺陷及用ScheduledThreadPoolExecutor解决

时间:2021-05-13 14:37:30

1.缺陷一:Timer由于内部只要一个线程,管理多个任务的时候,一个任务延时,后面的任务就会跟着延时。用下面的例子说明:

package com.dxz.timer;

import java.util.Timer;
import java.util.TimerTask;

public class TimerTaskTest {
private static long startTime;

public static void main(String[] args) {

// 创建一个定时task1
TimerTask task1 = new TimerTask() {

@Override
public void run() {
System.out.println(
"task1 excude ..." + (System.currentTimeMillis() - startTime));
try {
Thread.sleep(
3000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};
// 创建一个定时task2
TimerTask task2 = new TimerTask() {

@Override
public void run() {
System.out.println(
"task2 excude ..." + (System.currentTimeMillis() - startTime));
try {
Thread.sleep(
3000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};

Timer timer
= new Timer("TimerThread");
startTime
= System.currentTimeMillis();
// 第1个任务1s后,执行
timer.schedule(task1, 1000);
// 第2个任务3s后,执行
timer.schedule(task2, 3000);

}

}

结果:

task1 excude ...1001
task2 excude ...
4002

从上面的代码看出,第一个任务1s后执行,第二个任务3s后执行。实际上task2是在4s后才执行的,因为Timer内部是一个线程,而task1所需的时间超过了两个任务的间隔时间导致。下面使用ScheduledThreadPool解决上面的问题:

package com.dxz.timer;

import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolTest1 {

private static long startTime;

public static void main(String[] args) {
ScheduledExecutorService newExecutorService
= Executors.newScheduledThreadPool(2);

// 创建一个定时task1
TimerTask task1 = new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()
+ " excude ..."
+ (System.currentTimeMillis() - startTime) + "ms");
try {
Thread.sleep(
3000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};
// 创建一个定时task2
TimerTask task2 = new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()
+ " excude ..."
+ (System.currentTimeMillis() - startTime) + "ms");
try {
Thread.sleep(
3000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};

startTime
= System.currentTimeMillis();
// 第1个任务1000 表示1s后,执行
newExecutorService.schedule(task1, 1000, TimeUnit.MILLISECONDS);
// 第2个任务3000 表示3s后,执行
newExecutorService.schedule(task2, 3000, TimeUnit.MILLISECONDS);

}

}

结果:

pool-1-thread-1 excude ...1001ms
pool
-1-thread-2 excude ...3002ms

2、缺陷二:

package com.dxz.timer;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerTaskTest2 {
private static long startTime;

public static void main(String[] args) {
// 创建一个定时task1
TimerTask task1 = new TimerTask() {
@Override
public void run() {
throw new RuntimeException("运行时异常");
}
};
// 创建一个定时task2
TimerTask task2 = new TimerTask() {
@Override
public void run() {
System.out.println(
"task2 excude ..." + (System.currentTimeMillis() - startTime));
try {
Thread.sleep(
3000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
};

Timer timer
= new Timer("TimerThread");
startTime
= System.currentTimeMillis();
timer.schedule(task1,
100);
timer.scheduleAtFixedRate(task2,
new Date(), 1000);

}

}

结果:

task2 excude ...2
Exception in thread
"TimerThread" java.lang.RuntimeException: 运行时异常
at com.dxz.timer.TimerTaskTest2$
1.run(TimerTaskTest2.java:15)
at java.util.TimerThread.mainLoop(Timer.java:
555)
at java.util.TimerThread.run(Timer.java:
505)

使用ScheduledExecutorService来解决:

package com.dxz.timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadPoolTest2 {

private static long startTime;

public static void main(String[] args) {
ScheduledExecutorService newExecutorService
= Executors.newScheduledThreadPool(1);

// 创建一个定时task1
TimerTask task1 = new TimerTask() {
@Override
public void run() {
new RuntimeException();
}
};
// 创建一个定时task2
TimerTask task2 = new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()
+ " excude ..." + (System.currentTimeMillis() - startTime) + "ms");
}
};

startTime
= System.currentTimeMillis();
newExecutorService.schedule(task1,
0, TimeUnit.MILLISECONDS);
// 第2个任务3000 表示3s后,执行
newExecutorService.scheduleAtFixedRate(task2,1000, 1000, TimeUnit.MILLISECONDS);

}

}

结果:

pool-1-thread-1 excude ...1002ms
pool
-1-thread-1 excude ...2001ms
pool
-1-thread-1 excude ...3002ms
pool
-1-thread-1 excude ...4002ms