如何用Java编写周期性执行(定时任务)的代码?

2026-05-24 01:271阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1082个文字,预计阅读时间需要5分钟。

如何用Java编写周期性执行(定时任务)的代码?

最近遇到一个在线设备在线离线的判断问题,设计是每个长时间(通常是定时任务)检测一次设备是否在线。当检测到离线时,我们不能直接断定设备一定离线,而是需要重试测几遍,才能确认。

最近是遇到一个设备在线离线的判定问题,设计是每个多长时间(常规的定时任务)检测一次设备是否在前,当检测到里离线时,我们不能立马判断为离线,而是要在重试多测几次,只要一次成功就返回判定为在线,多次都不成功侧是离线,我这里相当了用ScheduledThreadPoolExecutor来实现,如有不足还请提出。如下:

ScheduledThreadPoolExecutor的介绍:

ScheduledThreadPoolExecutor,它可另行安排在给定的延迟后运行命令,或者定期执行命令。需要多个辅助线程时,或者要求 ThreadPoolExecutor 具有额外的灵活性或功能时,此类要优于Timer。

ScheduledThreadPoolExecutor的使用详解

当程序需要用到一个定时器处理问题的时候,并且需要处理的频率是很快的,这就需要一个稳定的定时器来保证数据的长久进行。ScheduledThreadPoolExecutor这个类就是个很好的选择。正常情况下,定时器我们都是用Timer和TimerTask这两个类就能完成定时任务,并且设置延长时间和循环时间间隔。
ScheduledThreadPoolExecutor也能完成Timer一样的定时任务,并且时间间隔更加准确。

误差说明:

我在后台程序看看一下Timer执行程序是有可能延迟1、2毫秒,如果是1秒执行一次的任务,1分钟有可能延迟60毫秒,一小时延迟3600毫秒,相当于3秒,实际用户看不出什么区别。 但是,如果我的程序需要每40毫秒就执行一次任务,如果还是有1、2毫秒的误差,1秒钟就有25毫秒的误差,大概40秒就有1秒的误差,十几分钟就有十几秒的误差,这对UI显示来说是延迟非常严重的了。 而我用ScheduledThreadPoolExecutor来做40毫秒的间隔任务,一般十几分钟才有1秒多的误差,这个还是能接受的。 这也是我用ScheduledThreadPoolExecutor这个类的原因。

使用Timer和TimerTask存在一些缺陷:

1.Timer只创建了一个线程。当你的任务执行的时间超过设置的延时时间将会产生一些问题。
2.Timer创建的线程没有处理异常,因此一旦抛出非受检异常,该线程会立即终止。
JDK 5.0以后推荐使用ScheduledThreadPoolExecutor。该类属于Executor Framework,它除了能处理异常外,还可以创建多个线程解决上面的问题

Timer和TimerTask的使用 :

这里就不做过多的描述了,重点在ScheduledThreadPoolExecutor。

Timer timer = new Timer();       timer.schedule(new TimerTask() {             @Override             public void run() {                 log.e("time:");               }         }, 2000, 40); //2000表示第一次执行任务延迟时间,40表示以后每隔多长时间执行一次run里面的任务

ScheduledThreadPoolExecutor的使用:

如何用Java编写周期性执行(定时任务)的代码?

import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger;   /**  * 设备在线延时检查检查  */ @Slf4j public class DelayedCheckDeviceSchedule {     public static final Integer CONNECT_TIME_OUT = 10000;   //引用的业务层   private ITblBaseService baseService = SpringContextHolder.getBean(ITblBaseService .class);     private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = null;     /**    * 需要延时检查的设备状态的设备id集合    */   public static Set<String> deviceSet = new HashSet<>();     /**    * 当前执行点    */   private AtomicInteger currentAtomicInteger = new AtomicInteger(1);       /**    * 初始化任务    * @param delay 延迟几秒执行    * @param checkCount 需要检测的次数    * @param deviceId 设备Id    * @param deviceType 设备类型    * @return    */   public boolean init(long delay, int checkCount, String deviceId, String deviceType) {     log.info("第一次初始化时间"+deviceId+":"+System.currentTimeMillis());     if (deviceSet.add(deviceId) && deviceConnectModel!=null) {       this.scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(4);       this.scheduledThreadPoolExecutor.schedule(new Runnable() {         @Override         public void run() {           executor(delay, checkCount, deviceId, deviceType);         }       }, delay, TimeUnit.SECONDS);       return true;     }     return false;   }     /**    * 执行体    */   private void executor(long delay, int checkCount, String deviceId, String deviceType) {     log.info("第"+currentAtomicInteger.get()+"执行时间"+deviceId+":"+System.currentTimeMillis());     if (deviceSet.contains(deviceId) && currentAtomicInteger.get() < (checkCount+1)) {       //执行逻辑                   //当满足条件时,停止任务         if(currentAtomicInteger.get()==checkCount){            //需要处理的逻辑             //停止任务           this.scheduledThreadPoolExecutor.shutdownNow();           deviceSet.remove(deviceId);         }else {           //下一次执行           currentAtomicInteger.getAndIncrement();           this.scheduledThreadPoolExecutor.schedule(new Runnable() {             @Override             public void run() {               executor(delay, checkCount, deviceId, deviceType);             }           }, delay, TimeUnit.SECONDS);              }     } else {       this.scheduledThreadPoolExecutor.shutdownNow();       this.scheduledThreadPoolExecutor = null;     }   }     /**    * 停止检测任务    * @param deviceId    * @return    */   public static boolean stop(String deviceId) {     return deviceSet.remove(deviceId);   }   }

在需要周期性检查的时候引入:

DelayedCheckDeviceSchedule delayedCheckDeviceSchedule = new DelayedCheckDeviceSchedule(); delayedCheckDeviceSchedule.init(10, 3, panModel.getDeviceId(), "pan");

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自由互联。

本文共计1082个文字,预计阅读时间需要5分钟。

如何用Java编写周期性执行(定时任务)的代码?

最近遇到一个在线设备在线离线的判断问题,设计是每个长时间(通常是定时任务)检测一次设备是否在线。当检测到离线时,我们不能直接断定设备一定离线,而是需要重试测几遍,才能确认。

最近是遇到一个设备在线离线的判定问题,设计是每个多长时间(常规的定时任务)检测一次设备是否在前,当检测到里离线时,我们不能立马判断为离线,而是要在重试多测几次,只要一次成功就返回判定为在线,多次都不成功侧是离线,我这里相当了用ScheduledThreadPoolExecutor来实现,如有不足还请提出。如下:

ScheduledThreadPoolExecutor的介绍:

ScheduledThreadPoolExecutor,它可另行安排在给定的延迟后运行命令,或者定期执行命令。需要多个辅助线程时,或者要求 ThreadPoolExecutor 具有额外的灵活性或功能时,此类要优于Timer。

ScheduledThreadPoolExecutor的使用详解

当程序需要用到一个定时器处理问题的时候,并且需要处理的频率是很快的,这就需要一个稳定的定时器来保证数据的长久进行。ScheduledThreadPoolExecutor这个类就是个很好的选择。正常情况下,定时器我们都是用Timer和TimerTask这两个类就能完成定时任务,并且设置延长时间和循环时间间隔。
ScheduledThreadPoolExecutor也能完成Timer一样的定时任务,并且时间间隔更加准确。

误差说明:

我在后台程序看看一下Timer执行程序是有可能延迟1、2毫秒,如果是1秒执行一次的任务,1分钟有可能延迟60毫秒,一小时延迟3600毫秒,相当于3秒,实际用户看不出什么区别。 但是,如果我的程序需要每40毫秒就执行一次任务,如果还是有1、2毫秒的误差,1秒钟就有25毫秒的误差,大概40秒就有1秒的误差,十几分钟就有十几秒的误差,这对UI显示来说是延迟非常严重的了。 而我用ScheduledThreadPoolExecutor来做40毫秒的间隔任务,一般十几分钟才有1秒多的误差,这个还是能接受的。 这也是我用ScheduledThreadPoolExecutor这个类的原因。

使用Timer和TimerTask存在一些缺陷:

1.Timer只创建了一个线程。当你的任务执行的时间超过设置的延时时间将会产生一些问题。
2.Timer创建的线程没有处理异常,因此一旦抛出非受检异常,该线程会立即终止。
JDK 5.0以后推荐使用ScheduledThreadPoolExecutor。该类属于Executor Framework,它除了能处理异常外,还可以创建多个线程解决上面的问题

Timer和TimerTask的使用 :

这里就不做过多的描述了,重点在ScheduledThreadPoolExecutor。

Timer timer = new Timer();       timer.schedule(new TimerTask() {             @Override             public void run() {                 log.e("time:");               }         }, 2000, 40); //2000表示第一次执行任务延迟时间,40表示以后每隔多长时间执行一次run里面的任务

ScheduledThreadPoolExecutor的使用:

如何用Java编写周期性执行(定时任务)的代码?

import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger;   /**  * 设备在线延时检查检查  */ @Slf4j public class DelayedCheckDeviceSchedule {     public static final Integer CONNECT_TIME_OUT = 10000;   //引用的业务层   private ITblBaseService baseService = SpringContextHolder.getBean(ITblBaseService .class);     private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = null;     /**    * 需要延时检查的设备状态的设备id集合    */   public static Set<String> deviceSet = new HashSet<>();     /**    * 当前执行点    */   private AtomicInteger currentAtomicInteger = new AtomicInteger(1);       /**    * 初始化任务    * @param delay 延迟几秒执行    * @param checkCount 需要检测的次数    * @param deviceId 设备Id    * @param deviceType 设备类型    * @return    */   public boolean init(long delay, int checkCount, String deviceId, String deviceType) {     log.info("第一次初始化时间"+deviceId+":"+System.currentTimeMillis());     if (deviceSet.add(deviceId) && deviceConnectModel!=null) {       this.scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(4);       this.scheduledThreadPoolExecutor.schedule(new Runnable() {         @Override         public void run() {           executor(delay, checkCount, deviceId, deviceType);         }       }, delay, TimeUnit.SECONDS);       return true;     }     return false;   }     /**    * 执行体    */   private void executor(long delay, int checkCount, String deviceId, String deviceType) {     log.info("第"+currentAtomicInteger.get()+"执行时间"+deviceId+":"+System.currentTimeMillis());     if (deviceSet.contains(deviceId) && currentAtomicInteger.get() < (checkCount+1)) {       //执行逻辑                   //当满足条件时,停止任务         if(currentAtomicInteger.get()==checkCount){            //需要处理的逻辑             //停止任务           this.scheduledThreadPoolExecutor.shutdownNow();           deviceSet.remove(deviceId);         }else {           //下一次执行           currentAtomicInteger.getAndIncrement();           this.scheduledThreadPoolExecutor.schedule(new Runnable() {             @Override             public void run() {               executor(delay, checkCount, deviceId, deviceType);             }           }, delay, TimeUnit.SECONDS);              }     } else {       this.scheduledThreadPoolExecutor.shutdownNow();       this.scheduledThreadPoolExecutor = null;     }   }     /**    * 停止检测任务    * @param deviceId    * @return    */   public static boolean stop(String deviceId) {     return deviceSet.remove(deviceId);   }   }

在需要周期性检查的时候引入:

DelayedCheckDeviceSchedule delayedCheckDeviceSchedule = new DelayedCheckDeviceSchedule(); delayedCheckDeviceSchedule.init(10, 3, panModel.getDeviceId(), "pan");

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自由互联。