java定时任务springboot,Java实现定时任务

  java定时任务springboot,Java实现定时任务

  

目录
java实现定时任务定时器TimerTask示例缺点ScheduledThreadPoolExecutor示例Spring定时任务示例原理

  00-1010JDK自带的库,有两种方式可以实现预定任务,一种是Timer,另一种是ScheduledThreadPoolExecutor。

  00-1010创建定时器会创建一个线程,可用于计划TimerTask任务。

  Timer有四种构造方法,可以指定Timer线程的名称,以及是否设置为守护线程。默认名称Timer- number,默认不是守护线程。

  主要有三种重要的方法:

  Cancel():终止任务调度,取消所有当前调度的任务,正在运行的任务不受影响。

  Purge():从任务队列中删除所有已取消的任务。

  Schedule:开始调度任务,并提供几种重载方法:

  Schedule (timertask任务,长延迟)被延迟,这意味着任务在毫秒级的延迟后执行一次。

  Schedule (timertask task,date time)在指定时间执行,而“task schedule (timertask task,long delay,long period)”在“time”执行一次,在延迟毫秒后每隔“period”毫秒执行一次“task schedule (timertask task,date firstTime,long period)”,在指定时间“firstTime”后每隔“period”毫秒执行一次“task”

  

java实现定时任务

公共类Timer test { public static void main(String[]args){ Timer Timer=new Timer( aa );Task task=新任务();timer.schedule(task,new Date(),1000);} }类任务扩展TimerTask { @ Override public void run(){ system . out . println(new Date());} } Output:thujul 07 14:50336002 CST 2022 thujul 07 14:50:03 CST 2022 thujul 07 14336050:04 CST 2022 thujul 07 14336050336005 CST 2022..

  

Timer+TimerTask

定时器是单线程的,不会抛出异常。定时任务一旦抛出异常,就会导致整个线程停止,也就是定时任务停止。

  00-1010由于定时器的缺陷,不建议使用定时器。建议使用ScheduledThreadPoolExecutor。

  ScheduledThreadPoolExecutor是Timer的替代,它是在JDK1.5中引入的,继承了ThreadPoolExecutor。它是一个基于线程池设计的调度任务类。

  主要调度方式:

  计划仅执行一次计划,(任务、延迟时间、延迟时间单位)

  ScheduleAtFixedRate以固定的频率进行调度。如果执行时间过长,下一次调度将被延迟,(任务,第一次执行的延迟时间,周期,时间单位)

  scheduleWithFixedDelay

  >延迟调度,一次任务执行完后加上延迟时间执行下一次任务,(任务,第一次执行的延迟时间,间隔时间,时间单位)

  

示例

public class TimerTest { public static void main(String[] args) throws Exception{ ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10); scheduledExecutorService.scheduleAtFixedRate( () -> System.out.println(new Date()), 1,3, TimeUnit.SECONDS); }}

  

Spring定时任务

Spring定时任务主要靠@Scheduled注解实现,corn,fixedDelay,fixedDelayString,fixedRate,fixedRateString五个参数必须指定其一,传两个或三个都会抛出异常

  

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Repeatable(Schedules.class)public @interface Scheduled {String CRON_DISABLED = ScheduledTaskRegistrar.CRON_DISABLED; // cron表达式String cron() default ""; // 时区String zone() default ""; // 从上一次调用结束到下一次调用之间的固定时间long fixedDelay() default -1; // 和fixedDelay意思相同,只是使用字符传格式,支持占位符。例如:fixedDelayString = "${time.fixedDelay}"String fixedDelayString() default ""; // 两次调用之间固定的毫秒数(不需要等待上次任务完成)long fixedRate() default -1; // 同上,支持占位符String fixedRateString() default ""; // 第一次执行任务前延迟的毫秒数long initialDelay() default -1; // 同上,支持占位符String initialDelayString() default "";}

示例

@Component@EnableSchedulingpublic class ScheduledTask { @Scheduled(fixedDelay = 1000) public void task(){ System.out.println("aaa"); }}

  

原理

项目启动ScheduledAnnotationBeanPostProcessorpostProcessAfterInitialization()方法扫描带有@Scheduled注解的方法:

  

@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {if (bean instanceof AopInfrastructureBean bean instanceof TaskScheduler bean instanceof ScheduledExecutorService) {// Ignore AOP infrastructure such as scoped proxies.return bean;}Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);if (!this.nonAnnotatedClasses.contains(targetClass) &&AnnotationUtils.isCandidateClass(targetClass, Arrays.asList(Scheduled.class, Schedules.class))) {Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);return (!scheduledMethods.isEmpty() ? scheduledMethods : null);});if (annotatedMethods.isEmpty()) {this.nonAnnotatedClasses.add(targetClass);if (logger.isTraceEnabled()) {logger.trace("No @Scheduled annotations found on bean class: " + targetClass);}}else {// Non-empty set of methodsannotatedMethods.forEach((method, scheduledMethods) -> // 调用processScheduled方法将定时任务的方法存放到任务队列中scheduledMethods.forEach(scheduled -> processScheduled(scheduled, method, bean)));if (logger.isTraceEnabled()) {logger.trace(annotatedMethods.size() + " @Scheduled methods processed on bean " + beanName +": " + annotatedMethods);}}}return bean;}
protected void processScheduled(Scheduled scheduled, Method method, Object bean) {try { // 创建任务线程Runnable runnable = createRunnable(bean, method); // 解析到定时任务方式的标记,解析到正确的参数后会设置为TRUE,如果在解析到了其他的参数就会抛出异常boolean processedSchedule = false;String errorMessage ="Exactly one of the cron, fixedDelay(String), or fixedRate(String) attributes is required";Set<ScheduledTask> tasks = new LinkedHashSet<>(4);// Determine initial delay 解析第一次的延迟(解析initialDelay参数)long initialDelay = scheduled.initialDelay();String initialDelayString = scheduled.initialDelayString();if (StringUtils.hasText(initialDelayString)) { // initialDelay不能小于0Assert.isTrue(initialDelay < 0, "Specify initialDelay or initialDelayString, not both");if (this.embeddedValueResolver != null) {initialDelayString = this.embeddedValueResolver.resolveStringValue(initialDelayString);}if (StringUtils.hasLength(initialDelayString)) {try {initialDelay = parseDelayAsLong(initialDelayString);}catch (RuntimeException ex) {throw new IllegalArgumentException("Invalid initialDelayString value "" + initialDelayString + "" - cannot parse into long");}}}// Check cron expression 解析cron表达式String cron = scheduled.cron();if (StringUtils.hasText(cron)) { // 解析时区String zone = scheduled.zone();if (this.embeddedValueResolver != null) {cron = this.embeddedValueResolver.resolveStringValue(cron);zone = this.embeddedValueResolver.resolveStringValue(zone);}if (StringUtils.hasLength(cron)) {Assert.isTrue(initialDelay == -1, "initialDelay not supported for cron triggers");processedSchedule = true;if (!Scheduled.CRON_DISABLED.equals(cron)) {TimeZone timeZone;if (StringUtils.hasText(zone)) {timeZone = StringUtils.parseTimeZoneString(zone);}else {timeZone = TimeZone.getDefault();}tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));}}} // 第一次延迟参数小于0,默认为0// At this point we dont need to differentiate between initial delay set or not anymoreif (initialDelay < 0) {initialDelay = 0;}// Check fixed delay 解析fixedDelay参数long fixedDelay = scheduled.fixedDelay();if (fixedDelay >= 0) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;tasks.add(this.registrar.scheduleFixedDelayTask(new FixedDelayTask(runnable, fixedDelay, initialDelay)));}String fixedDelayString = scheduled.fixedDelayString();if (StringUtils.hasText(fixedDelayString)) {if (this.embeddedValueResolver != null) {fixedDelayString = this.embeddedValueResolver.resolveStringValue(fixedDelayString);}if (StringUtils.hasLength(fixedDelayString)) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;try {fixedDelay = parseDelayAsLong(fixedDelayString);}catch (RuntimeException ex) {throw new IllegalArgumentException("Invalid fixedDelayString value "" + fixedDelayString + "" - cannot parse into long");}tasks.add(this.registrar.scheduleFixedDelayTask(new FixedDelayTask(runnable, fixedDelay, initialDelay)));}}// Check fixed rate 解析fixedRate参数long fixedRate = scheduled.fixedRate();if (fixedRate >= 0) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, initialDelay)));}String fixedRateString = scheduled.fixedRateString();if (StringUtils.hasText(fixedRateString)) {if (this.embeddedValueResolver != null) {fixedRateString = this.embeddedValueResolver.resolveStringValue(fixedRateString);}if (StringUtils.hasLength(fixedRateString)) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;try {fixedRate = parseDelayAsLong(fixedRateString);}catch (RuntimeException ex) {throw new IllegalArgumentException("Invalid fixedRateString value "" + fixedRateString + "" - cannot parse into long");}tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, initialDelay)));}}// Check whether we had any attribute set // 如果五个参数一个也没解析到,抛出异常Assert.isTrue(processedSchedule, errorMessage);// Finally register the scheduled tasks // 并发控制将任务队列存入注册任务列表synchronized (this.scheduledTasks) {Set<ScheduledTask> regTasks = this.scheduledTasks.computeIfAbsent(bean, key -> new LinkedHashSet<>(4));regTasks.addAll(tasks);}}catch (IllegalArgumentException ex) {throw new IllegalStateException("Encountered invalid @Scheduled method " + method.getName() + ": " + ex.getMessage());}}
将任务解析并添加到任务队列后,交由ScheduledTaskRegistrar类的scheduleTasks方法添加(注册)定时任务到环境中

  

protected void scheduleTasks() { if (this.taskScheduler == null) { //获取ScheduledExecutorService对象,实际上都是使用ScheduledThreadPoolExecutor执行定时任务调度 this.localExecutor = Executors.newSingleThreadScheduledExecutor(); this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor); } if (this.triggerTasks != null) { for (TriggerTask task : this.triggerTasks) { addScheduledTask(scheduleTriggerTask(task)); } } if (this.cronTasks != null) { for (CronTask task : this.cronTasks) { addScheduledTask(scheduleCronTask(task)); } } if (this.fixedRateTasks != null) { for (IntervalTask task : this.fixedRateTasks) { addScheduledTask(scheduleFixedRateTask(task)); } } if (this.fixedDelayTasks != null) { for (IntervalTask task : this.fixedDelayTasks) { addScheduledTask(scheduleFixedDelayTask(task)); } }}private void addScheduledTask(@Nullable ScheduledTask task) { if (task != null) { this.scheduledTasks.add(task); }}
到此这篇关于Java Spring分别实现定时任务方法的文章就介绍到这了,更多相关Java 定时任务内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: