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() + ":执行");
    }
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

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

(0)
上一篇 2022年10月11日 上午9:36
下一篇 2022年10月11日 上午9:46


相关推荐

  • 如何把内网IP映射到公网IP

    如何把内网IP映射到公网IP 鸽子出品2017-12-0522:28:22我们讲了如何搭建网站,可是有很多小伙伴私信跟我说怎么映射,今天我就教大家如何把内网地址映射到公网!我们所需要的工具有: 内网IP(这个是品,也是必有的!) nat123(这是映射软件,百度上都能搜索到) 有些小伙伴会问: 这个软件是什么操作系统啊? 这个软件免费吗? 当然官网上有windows版…

    2022年5月18日
    129
  • can总线板卡_CAN接口

    can总线板卡_CAN接口现有市场下,智能化程度越来越高,特别是AGV、机器人、物流车、动力电池检测等等行业中工控机应用越来越频繁。然而这些产品核心控制器与电池都是走的CAN总线通讯,而工控机本身是没有CAN通讯,那么工控机就需要通讯桥梁(025-68250795)来扩展CAN通道。而在工控机当中有nimipcie接口,如此就用可以用minipcie接口转CAN的一个模块来实现扩充CAN口。miniPCIe接口CAN卡是PCIExpressmini卡槽的工控机或单板电脑快速扩展CAN通道的利器。产品特性PCIExpr

    2025年9月1日
    6
  • 常用webservice方法_太极拳初学入门的基本要领

    常用webservice方法_太极拳初学入门的基本要领1.什么是webservice先来考虑一个问题,如果我们要在自己的程序里面展示天气预报,那怎么弄?正确的做法是我们发送一个请求到一个系统,他会给我们返回来天气情况。这个就是一个webservice。天气预报系统就相当于webservice的服务端,我们的系统就相当于客户端。2.如何调用别人发布的webservice

    2026年2月9日
    5
  • C++实现内存池

    C++实现内存池1 内存池设计 1 1 目的在给定的内存 buffer 上建立内存管理机制 根据用户需求从该 buffer 上分配内存或者将已经分配的内存释放回 buffer 中 1 2 要求尽量减少内存碎片 平均效率高于 C 语言的 malloc 和 free 1 3 设计思路将 buffer 分为四部分 第 1 部分是 mem pool 结构体 第 2 部分是内存映射表 第 3 部分是内存 chunk 结构体缓冲区 第 4 部分是实际

    2026年3月17日
    1
  • Android如何搭建FTP服务器

    Android如何搭建FTP服务器如何使用我们的手机搭建 ftp 服务 以实现局域网内共享手机文件呢

    2025年10月9日
    6
  • Nano Banana Pro免费吗?国内使用保姆级教程,8大场景提示词直接抄

    Nano Banana Pro免费吗?国内使用保姆级教程,8大场景提示词直接抄

    2026年3月13日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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