spring任务调度scheduled_golang 任务调度

spring任务调度scheduled_golang 任务调度1、任务调度接口TaskScheduler提供了多种方法来调度将来某个时间点要运行的任务。2、触发器Trigger实现PeriodicTrigger和CronTrigger。3、@Scheduled注解创建定时任务4、@Async注解异步方法执行,value属性指定任务执行器。5、task:scheduler、task:executor创建调度器和执行器…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

任务调度接口:TaskScheduler

除了TaskExecutor抽象之外,Spring 3.0还引用了任务调度接口 TaskScheduler,它提供了多种方法来调度将来某个时间点要运行的任务。

public interface TaskScheduler { 
   
 
    ScheduledFuture schedule(Runnable task, Trigger trigger); //通过触发器来决定task是否执行
 
    ScheduledFuture schedule(Runnable task, Date startTime);  //在starttime的时候执行一次
 
    ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period); //从starttime开始每个period时间段执行一次task
 
    ScheduledFuture scheduleAtFixedRate(Runnable task, long period);  //每隔period执行一次
 
    ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay); //从startTime开始每隔delay长时间执行一次
 
    ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay); //每隔delay时间执行一次
}

固定速率和固定延迟方法用于简单的、周期性的执行,但是使用 Trigger 的方法要灵活得多。

Trigger接口

TaskScheduler中将会使用到Trigger对象,Trigger接口用于计算任务的下次执行触发时间。通过实现Trigger接口可以实现自定义触发器来执行执行task。

public interface Trigger { 
   
 
    Date nextExecutionTime(TriggerContext triggerContext);
}

TriggerContext 保存 Trigger 接口任务执行调度的信息。它封装了所有相关的数据,如果需要,将来可以对其进行扩展。TriggerContext是一个接口(默认情况下使用SimpleTriggerContext实现)。在这里,您可以看到哪些方法可用于触发器实现。

public interface TriggerContext { 
   
 
    Date lastScheduledExecutionTime();
 
    Date lastActualExecutionTime();
 
    Date lastCompletionTime();
}

Trigger实现

Spring也提供了触发器接口的两个默认的实现类:PeriodicTriggerCronTrigger
spring任务调度scheduled_golang 任务调度

PeriodicTrigger

用于定期执行的Trigger。它有两种模式:

  • fixedRate:两次任务开始时间之间间隔指定时长
  • fixedDelay: 上一次任务的结束时间与下一次任务开始时间“间隔指定时长

默认情况下PeriodicTrigger使用了fixedDelay模式

CronTrigger

通过Cron表达式来生成调度计划。比如:scheduler.schedule(task, new CronTrigger(“0 15 9-17 * * MON-FRI”)); 表示 “工作日的9点到17点,每个小时的15分执行一次”。

cron表达式含义见《cron表达式

Spring对cron表达式的支持,是由CronSequenceGenerator来实现的,不依赖于别的框架。下面给出一个Demo感受下:

public static void main(String[] args) { 
   
    CronSequenceGenerator generator = new CronSequenceGenerator("0 15 * * * MON-FRI");

    Date next = generator.next(new Date());
    System.out.println(next); //Mon Apr 22 17:15:00 CST 2021
    System.out.println(generator.next(next)); //Mon Apr 22 18:15:00 CST 2021

}

TaskScheduler接口

Spring任务调度器的核心接口,定义了执行定时任务的主要方法,主要根据任务的不同触发方式调用不同的执行逻辑,其实现类都是对JDK原生的定时器或线程池组件进行包装,并扩展额外的功能。

TaskScheduler实现

与Spring的TaskExecutor抽象一样,TaskScheduler 主要好处是应用程序的调度需求与部署环境解耦,应用程序本身不应该直接创建线程。

TaskScheduler有如下实现类 ConcurrentTaskSchedulerThreadPoolTaskScheduler
spring任务调度scheduled_golang 任务调度

ConcurrentTaskScheduler

以单个线程方式执行定时任务,适用于简单场景。

public class testTaskExecutor { 
   
    public static void main(String[] args) { 
   
        ConcurrentTaskScheduler taskScheduler = new ConcurrentTaskScheduler();

        // 执行任务
        // 执行一次
        taskScheduler.execute(() -> System.out.println(Thread.currentThread().getName() + " 我只会被执行一次~~~"));
        // 周期性执行
        taskScheduler.schedule(() -> System.out.println(Thread.currentThread().getName() + " 我会被多次执行~~~"), new CronTrigger("0/2 * * * * ?"));

        // 此处:若你有周期性的任务,这里不要shutdown()
        //taskScheduler.shutdown();
    }
}

执行结果:
spring任务调度scheduled_golang 任务调度

执行的线程都是一样的。

ThreadPoolTaskScheduler

public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport 
                   implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, TaskScheduler

除实现了TaskScheduler接口中的方法外,它还包含了一些对ScheduledThreadPoolExecutor进行操作的接口,大多数场景下都使用它来进行任务调度。

任务调度Demo

package TaskSchedulerDemo;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;

public class testTaskExecutor { 
   
    public static void main(String[] args) { 
   
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(6);
        taskScheduler.initialize(); // 务必调用此方法来手动启动

        // 执行任务
        // 执行一次
        taskScheduler.execute(new Runnable() { 
   
            @Override
            public void run() { 
   
                System.out.println(Thread.currentThread().getName() + " 我只会被执行一次~~~");
            }
        });
        
        // lambda表达式,多用于匿名内部类、forEach()方法等。小括号()用于传参,大括号{}用于执行相关操作、返回值等。
        // taskScheduler.execute(() -> System.out.println(Thread.currentThread().getName() + " 我只会被执行一次~~~"));
        // 周期性执行
        taskScheduler.schedule(() -> System.out.println(Thread.currentThread().getName() + " 我会被多次执行~~~"), new CronTrigger("0/2 * * * * ?"));

        // 此处:若你有周期性的任务,这里不要shutdown()
        //taskScheduler.shutdown();
    }
}

执行结果:
spring任务调度scheduled_golang 任务调度

注:使用前必须得先调用initialize()【初始化方法】。shutDown()方法执行完后可以关闭线程。

注入方式

1、applicationContext.xml配置文件配置ThreadPoolTaskScheduler:

<context:component-scan base-package="TaskSchedulerDemo" />
<bean id = "taskScheduler" class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
    <property name="poolSize" value = "5"></property>
</bean>

2、定义一个任务DataSimulation:

package TaskSchedulerDemo;

import org.springframework.stereotype.Component;
import java.util.Random;

@Component
public class DataSimulation implements Runnable { 
   
    @Override
    public void run() { 
   
        Random random = new Random();
        System.out.println("[" + Thread.currentThread().getName() + "]" +"-" + random.nextInt(10));
    }
}

3、SchedulerFacotory类注入TaskScheduler 对象:

@Component
public class SchedulerFacotory { 
   
    @Autowired
    public TaskScheduler scheduler;

    public TaskScheduler getScheduler() { 
   
        return scheduler;
    }

    public void setScheduler(TaskScheduler scheduler) { 
   
        this.scheduler = scheduler;
    }

    public void schedulerFactory(){ 
   
        scheduler.schedule(new DataSimulation(), new CronTrigger("0/2 * * * * ?"));
    }
}

4、调用:

public class testTaskScheduler { 
   
    public static void main(String[] args) { 
   
        ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { 
   "applicationContext.xml"});

        SchedulerFacotory sf = (SchedulerFacotory)context.getBean("schedulerFacotory");
        sf.schedulerFactory();
    }
}

运行结果:
spring任务调度scheduled_golang 任务调度

注解方式(自动启动)

1、Spring配置文件applicationContext.xml中注解配置如下:

<!--添加注解的扫描包-->
<context:component-scan base-package="TaskSchedulerAnnoStartDemo" />
<!--配置注解驱动-->
<task:annotation-driven />
<task:scheduler id="myScheduler" pool-size="5"/>

<task:annotation-driven />还可以通过scheduler,指定具体的任务调度器。

<!--添加注解的扫描包-->
<context:component-scan base-package="TaskSchedulerAnnoStartDemo" />

<!--配置注解驱动 多个scheduler时,可以指定scheduler-->
<task:annotation-driven scheduler="myScheduler2"/>

<task:scheduler id="myScheduler" pool-size="5"/>
<bean id = "myScheduler2" class="org.springframework.scheduling.concurrent.ConcurrentTaskScheduler">
</bean>

注:<task:scheduler id=“myScheduler” pool-size=“5”/> 默认使用 ThreadPoolTaskScheduler

2、创建SchedulerPoolService,并在service中使用 @Scheduled 注解创建定时任务

package TaskSchedulerDemo;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
public class SchedulerPoolService { 
   

    @Scheduled(cron = "0/3 * * * * ?")
    public void task1(){ 
   
        Thread thread =  Thread.currentThread();
        System.out.println("[" + Thread.currentThread().getName() + "]" + new Date() + "-task1-id:" + thread.getId() + ",group:" + thread.getThreadGroup());
    }

    @Scheduled(fixedDelay = 5000)
    public void task2(){ 
   
        Thread thread =  Thread.currentThread();
        System.out.println("[" + Thread.currentThread().getName() + "]" + new Date() + "-task2-id:" + thread.getId() + ",group:" + thread.getThreadGroup());
    }
}

3、加载配置文件即可不需要手动启动任务

public class testTaskExecutor { 
   
    public static void main(String[] args) { 
   
        ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { 
   "TaskSchedulerDemo/applicationContext.xml"});
    }
}

运行结果:
spring任务调度scheduled_golang 任务调度

完全注解开发(自动启动)

还可以结合配置类 @Configuration@EnableScheduling 开启配置计划任务,实现完全注解开发,不需要手动启动任务
配置类SpringConfig:

@Configuration
@ComponentScan("TaskSchedulerAnnoStartDemo")
@EnableScheduling // 开启配置计划任务
public class SpringConfig { 
   
    @Bean
    public TaskScheduler getTaskScheduler(){ 
   
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(5);

        return threadPoolTaskScheduler;
    }
}

启动类:

public class testTaskExecutor { 
   
    public static void main(String[] args) { 
   
        //ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"TaskSchedulerAnnoStartDemo/applicationContext.xml"});
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    }
}

运行结果:
spring任务调度scheduled_golang 任务调度

Spring异步执行

Spring默认的事件机制是同步的。举个例子:

@Service
public class SchedulerPoolService { 
   
    @Scheduled(fixedDelay = 3000)
    public void task(){ 
   
        Thread thread =  Thread.currentThread();
        try { 
   
            Thread.sleep(5000);
        } catch (InterruptedException e) { 
   
            e.printStackTrace();
        }
        System.out.println("[" + Thread.currentThread().getName() + "]"+ "[" + new Date() + "]"+"task-id:" + thread.getId() + ",group:" + thread.getThreadGroup());
    }
}

在原先service增加触发时间打印,而且sleep(5000)。

运行结果:
spring任务调度scheduled_golang 任务调度

可以看出,任务每8秒执行一次,是轮询秒数(3秒)+ 单次任务执行时间(5秒),说明任务是同步执行。

Spring为任务调度和异步方法执行提供注释支持。

@Async 注解方法

有时候需要任务异步执行,不然太耗时,Spring提供注解 @Async 标注异步方法执行

@Service
public class SchedulerPoolService { 
   
    //此注解为异步方法注解,如果注解到类上,表示此类的所有方法都为异步方法
    @Async()
    @Scheduled(fixedDelay = 3000)
    public void task(){ 
   
        Thread thread =  Thread.currentThread();
        try { 
   
            Thread.sleep(5000);
        } catch (InterruptedException e) { 
   
            e.printStackTrace();
        }
        System.out.println("[" + Thread.currentThread().getName() + "]"+ "[" + new Date() + "]"+"task-id:" + thread.getId() + ",group:" + thread.getThreadGroup());
    }
}

运行结果:
spring任务调度scheduled_golang 任务调度

可以看出,任务每3秒执行一次,而且线程号也不一样,说明是异步执行。

@EnableAsync 注解类

还可以通过 @EnableAsync 注解服务类:

@Service
@EnableAsync
public class SchedulerPoolService { 
   
    @Async()
    @Scheduled(fixedDelay = 3000)
    public void task(){ 
   
        Thread thread =  Thread.currentThread();
        try { 
   
            Thread.sleep(5000);
        } catch (InterruptedException e) { 
   
            e.printStackTrace();
        }
        System.out.println("[" + Thread.currentThread().getName() + "]"+ "[" + new Date() + "]"+"task-id:" + thread.getId() + ",group:" + thread.getThreadGroup());
    }
}

调用:

public class TaskSchedulerTest { 
   
    public static void main(String[] args) { 
   
        ApplicationContext context = new AnnotationConfigApplicationContext(TaskSchedulerDemo.SpringConfig.class);
    }
}

运行结果:
spring任务调度scheduled_golang 任务调度

一般 @EnableScheduling@EnableAsync 都会结合 @Configuration 使用,用于配置类。
@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {

}

@Async 指定执行器

由上面例子结果看出,@Async 注解默认使用任务执行器 SimpleAsyncTaskExecutor,而此实现每次执行一个提交的任务时候都会新建一个线程,没有线程的复用,一般使用ThreadPoolTaskExecutor 来代替。

当需要指定执行器时,可以使用@Async注解的 value属性

@Service
public class SchedulerPoolService { 
   

    @Async("taskExecutor")
    @Scheduled(fixedDelay = 3000)
    public void task(){ 
   
        Thread thread =  Thread.currentThread();
        try { 
   
            Thread.sleep(5000);
        } catch (InterruptedException e) { 
   
            e.printStackTrace();
        }
        System.out.println("[" + Thread.currentThread().getName() + "]"+ "[" + new Date() + "]"+"task-id:" + thread.getId() + ",group:" + thread.getThreadGroup());
    }
}

applicationContext.xml中注解配置如下:

<bean id = "taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value = "5"></property>
    <property name = "maxPoolSize" value="10"></property>
    <property name="queueCapacity" value="25"></property>
</bean>

也可以使用 task:executor 配置,下文会讲解。

task命名空间

从Spring 3.0开始,有一个用于配置TaskExecutor和TaskScheduler实例的XML命名空间。它还提供了一种便利的方法来配置要用触发器调度的任务。

scheduler元素

创建具有指定线程池大小的ThreadPoolTaskScheduler实例。

<task:scheduler id="scheduler" pool-size="10"/>

如果不提供“池大小”属性,默认线程池将只有一个线程。调度程序没有其他配置选项。

executor元素

创建一个ThreadPoolTaskExecutor实例。

<task:executor id="executor" pool-size="10"/>

“executor”元素比“scheduler”元素支持更多的配置选项。首先,ThreadPoolTaskExecutor的线程池本身更具可配置性,pool-size 可以使得执行程序的线程池具有不同的核心值和最大大小,而不是单一大小。

<task:executor id="executorWithPoolSizeRange" pool-size="5-25" queue-capacity="100"/>

id 属性值可以用作指定执行器

@Async("executorWithPoolSizeRange")
public void foo() { 
   
    System.out.println("foo, " + Thread.currentThread().getName());
}

queue-capacity 主要思想是,当提交任务时,如果当前活跃线程的数量小于 core size,执行器将首先尝试使用空闲线程。如果已经达到 core size,那么只要队列的容量未满,任务就会被添加到队列中。 只有在达到queue-capacity时,执行器才会创建一个超出core size的新线程。如果已达到 max size,则执行程序将拒绝该任务。

默认情况下,队列是无限的,但这不是理想的配置,因为如果在所有池线程繁忙时向队列添加了足够的任务,就会导致outofmemoryerror错误。此外,如果队列是无限的,那么max size根本不起作用。因为执行器将总是在线程数超出core size时,将新建的线程加入队列。一个队列必须是有限的。

scheduled-tasks元素

可以通过 scheduled-tasks 配置要调度的任务。

<task:scheduled-tasks scheduler="myScheduler">
    <task:scheduled ref="beanA" method="methodA" fixed-delay="5000" initial-delay="1000"/>
    <task:scheduled ref="beanB" method="methodB" fixed-rate="5000"/>
    <task:scheduled ref="beanC" method="methodC" cron="*/5 * * * * MON-FRI"/>
</task:scheduled-tasks>
 
<task:scheduler id="myScheduler" pool-size="10"/>

pojo:

@Service
public class beanA{ 
   
 
    public void methodA() { 
   
        System.out.println(Thread.currentThread().getName() + ":执行");
    }
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/183254.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • MongoDB获得短暂的

    MongoDB获得短暂的

    2021年12月17日
  • 继续安利两个漫画App

    继续安利两个漫画App之前安利了很多漫画App~今天继续,以防被用o(>ω<)o玄猫漫画飒漫画回复“1051”下载玄猫漫画+飒漫画回复666给Yama买一块大白兔…

  • Sublime Text3 如何安装、删除及更新插件

    Sublime Text3 如何安装、删除及更新插件1、打开SublimeText3,按Ctrl+`(和qq输入法快捷切换冲突,可以修改qq的输入法切换热键)2、复制粘黏以下代码添加至命令行,然后回车(功能:安装插件的工具,有了它,以后安装其他插件更方便)importurllib.request,os;pf=’PackageControl.sublime-package’;ipp=sublime.inst…

  • 现场校时错乱分析,开启NTP校时延迟分析以及部署建议「建议收藏」

    现场校时错乱分析,开启NTP校时延迟分析以及部署建议「建议收藏」1.问题背景描述2021年7月23日宜春现场出现一台信号机在应该跑早高峰方案的时候,实际上跑了凌晨的方案,从而造成现场车辆拥堵的问题,客户进行了投诉并要求给出解释和解决方案。2.问题排查和分析排查过程中发现宜春现场的校时配置十分混乱。现场存在NTP,GPS,平台校时三种模式同时进行校时的情况。并且现场并不止有一个平台,也就是通过平台校时这个方式的校时源有多种。所以可以得知的是,现场的信号机在较多情况下同时会接受3-5种不同的校时源进行校时。3.同时有多种不同校时源下存在的风险信号机是一个时

  • 怎么用python3画烟花?代码是什么?[通俗易懂]

    怎么用python3画烟花?代码是什么?[通俗易懂]我们可以用python做很多好玩的事情哦~包括制作动态的视频,之前小编就教大写编写过制作内容,现在给大家想到了更好玩的事情,就是编写个烟花代码出来,有兴趣的小伙伴可以看下呢~实施步骤:一、导入海龟

  • django的orm查询方法_查看django版本命令

    django的orm查询方法_查看django版本命令前言查找是数据库操作中一个非常重要的技术。查询一般就是使用filter、exclude以及get三个方法来实现。我们可以在调用这些方法的时候传递不同的参数来实现查询需求。在ORM层面,这些查询条件都

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号