java实现定时任务的几种方式及更种应用场景

大家好,这是第一次与大家在这里相遇,只是把自己学习到内容和大家一起
分享并且进行讨论,如果有哪里不对希望大家多多点评哦!!!

  1. 使用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框架实现定时任务(因为没有真正的使用过)所以在此就不给大家进行介绍了。。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值