Timer类注意事项
Java的一个Timer对象可以执行多个Timertask任务,但是一个Timer对象本身只有一个线程,如果向他提交多个task,并且某个task相当耗时的话,其他的task即使到了执行时间,仍然会等之前的task执行完毕。更有问题,如果前一个task抛出了异常导致线程终止,后面的task将无法执行。
Timer 是一种定时器工具,用来在一个后台线程计划执行指定任务,这些任务可以被执行一次,也可以被定期执行。每个 Timer 对象对应一个后台线程,顺序地执行所有计时器任务。如果完成某个计时器任务的时间太长,那么它会“独占”计时器的任务执行线程,从而可能延迟后续任务的执行。对 Timer 对象最后的引用完成并且所有未处理的任务都已执行完成后,计时器的任务执行线程会正常终止(并且成为垃圾回收的对象)。TimerTask是一个抽象类,实现了Runable接口,它的子类代表一个可以被Timer计划的任务。
Timer类的schedule和scheduleAtFixedRate的区别:
schedule和 scheduleAtFixedRate的区别在于,schedule以固定的相对时间间隔执行,如果某一次执行被延时了,往后的执行的执行时间也会相对延时;而scheduleAtFixedRate是以绝对的时间间隔执行,如果某一次执行被延时,它的后一次执行的延时将会缩短(scheduleAtFixedRate会把已经过去的时间也作为周期执行)。schedule注重的是时间间隔的稳定,而scheduleAtFixedRate注重的是执行频率的稳定。
示例如下:
timerForDims = new Timer();
timerForDims.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
updateDim();
}
}, Calendar.getInstance().getTime(), 10 * 60 * 1000);
//每日3点从离线表里读取老用户ID存入redis
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 3);
String beforeDay = TimeUtil.getBeforeDay();
RefreshHiveOldUsers(beforeDay);
timerForOldUsers = new Timer();
timerForOldUsers.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
RefreshHiveOldUsers(beforeDay);
} catch (SQLException e) {
logger.error("RefreshOldUser: " + e.getMessage());
}
}
}, calendar.getTime(), 24 * 60 * 60 * 1000);