大家好,这是第一次与大家在这里相遇,只是把自己学习到内容和大家一起
分享并且进行讨论,如果有哪里不对希望大家多多点评哦!!!
- 使用java.util.Timer工具类
package com.msxt.service;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimerDemo {
public static String getCurrentTime() {
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(date);
}
public static void main(String[] args) throws InterruptedException {
System.out.println("main start" + getCurrentTime());
startTimer();
Thread.sleep(5 * 1000);
System.out.println("main end" + getCurrentTime());
}
public static void startTimer() {
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
// 写你自己的业务逻辑代码即可
System.out.println("timerTask run" + getCurrentTime());
}
};
Timer timer = new Timer();
timer.schedule(timerTask, 0);
}
}
代码执行结果:
main start: 2020-05-21 10:21:39
timerTask run: 2020-05-21 10:21:39
main end: 2020-05-21 10:21:44
在调用startTimer方法时,执行定时器中任务,然后调用了Timer对象,调用了他的方法schedule,Timer类有多个带不同参数的schedule方法。这里用到的是:
public void schedule(TimerTask task, long delay)
该方法的含义是指,定时器延迟delay(毫秒) 然后执行task任务。
public void schedule(TimerTask task, Date time)
此方法与上面的区别:是到某个时间time点去执行task任务,而且当你系统时间大于了该参数时间,立即执行该任务。
main start: 2020-05-21 10:21:39
timerTask run: 2020-05-21 10:21:39
两个是同时执行的,因为咱们这里将timer.schedule(timerTask, 0)这里的delay参数设置为零,所以会立即执行。但是我们设置Thread睡5秒之后打印信息。但是咱们发现个奇怪的现象啊就是当我们main主线程都结束了,但是执行定时器创建的线程执行完之后后台线程不会立即结束,需要等待垃圾回收,但java的待垃圾回收是无法通过代码控制的,而是由虚拟机控制的。
后来看看他的源码发现,在new Timer的时候就创建了定时器的线程(守护线程),
守护进程的含义: 当java程序中所有工作进程退出后,守护进程就会自动退出的。而在Timer源码中有个构造方法
public Timer(boolean isDaemon)
Timer timer = new Timer(“任务定时器”,false);//用户线程
Timer timer = new Timer();//用户线程
Timer timer = new Timer(true);//守护线程
根据自己功能实现去进行设置。
2. 使用spring提供的@Scheduled注解方式
@Component
@EnableScheduling//在项目中放到启动类上或者当前的测试类上
public class test(){
@Scheduled(cron="0/10 * * * * ?")
public void runTest1(){
System.out.println("*****cron表达式*********");
}
@Scheduled(fixedRate = 1000 * 10)
public void runTest2(){
System.out.println("*****fixeddRate参数*********");
}
@Scheduled(fixedDelay= 10000)
public void runTest3(){
System.out.println("*****fixedDelay参数*********");
}
}
@EnableScheduling 注解的作用是发现注解@Scheduled的任务并后台执行。
cron、fixedRate、fixedDelay三个参数是用来控制定时任务执行时间的,这三种方式都是设置每隔十秒执行一次。
在其他的博主中找到了cron表达式的定义:
“0 0 12 * * ?” 每天中午12点触发
“0 15 10 ? * *” 每天上午10:15触发
“0 15 10 * * ?” 每天上午10:15触发
“0 15 10 * * ? *” 每天上午10:15触发
“0 15 10 * * ? 2005” 2005年的每天上午10:15 触发
“0 * 14 * * ?” 在每天下午2点到下午2:59期间的每1分钟触发
“0 0/5 14 * * ?” 在每天下午2点到下午2:55期间的每5分钟触发
“0 0/5 14,18 * * ?” 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
“0 0-5 14 * * ?” 在每天下午2点到下午2:05期间的每1分钟触发
“0 10,44 14 ? 3 WED” 每年三月的星期三的下午2:10和2:44触发
“0 15 10 ? * MON-FRI” 周一至周五的上午10:15触发
“0 15 10 15 * ?” 每月15日上午10:15触发
“0 15 10 L * ?” 每月最后一日的上午10:15触发
“0 15 10 ? * 6L” 每月的最后一个星期五上午10:15触发
“0 15 10 ? * 6L 2002-2005” 2002年至2005年的每月的最后一个星期五上午10:15触发
“0 15 10 ? * 6#3” 每月的第三个星期五上午10:15触发
0 6 * * * 每天早上6点
0 /2 * * 每两个小时
0 23-7/2,8 * * * 晚上11点到早上8点之间每两个小时,早上八点
0 11 4 * 1-3 每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点
点击生成cron自动生成器
大家需要注意的是spring提供的@Scheduled的注解方式定时任务默认是单线程的,可以查看源码
@ConfigurationProperties("spring.task.scheduling")
public class TaskSchedulingProperties {
private final TaskSchedulingProperties.Pool pool = new TaskSchedulingProperties.Pool();
...
...
public static class Pool {
private int size = 1;
public Pool() {
}
public int getSize() {
return this.size;
}
public void setSize(int size) {
this.size = size;
}
}
}
由此可见spring提供的调度器是默认采用单线程的线程池。
这样会导致如果一个定时任务发生阻塞,将会影响其他定时任务的执行,因此我们需要配置多线程执行来解决此问题。
多线程解决方案
springboot工程
application.properties中添加如下配置即可
spring.task.scheduling.pool.size=10
spring.task.scheduling.thread-name-prefix=schedule-test
还可以写成配置类以及同一任务的异步执行(下次任务将在下一个配置时间开始,不等待当前任务执行完毕)
import java.util.concurrent.Executor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
@EnableAsync
public class AsyncConfig {
/*
* 此处成员变量应该使用@Value从配置中读取
*/
private int corePoolSize = 10;
private int maxPoolSize = 200;
private int queueCapacity = 10;
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.initialize();
return executor;
}
}
大家还要注意的是这个定时任务仅仅只是一个单机版本的,当你们需要部署到服务器上而且集群环境的时候应该去考虑,如何解决某个定时任务多次执行的问题。给大家提供博主地址:https://www.cnblogs.com/coloz/p/12697536.html
使用quarz框架实现定时任务(因为没有真正的使用过)所以在此就不给大家进行介绍了。。