作者:Mars酱
声明:本文章由Mars酱原创,部分内容来源于网络,如有疑问请联系本人。
转载:欢迎转载,转载前先请联系我!
前言
JDK自带的Timer是无法做到多任务并发的,那么我们怎么处理多任务定时的并发问题呢?这章节Mars酱来研究下。
Mars酱能想到的就是多线程、线程池这些关键字。
ScheduledExecutorService
ScheduledExecutorService是一个继承ExecutorService的接口类,ExecutorService 这个类Mars酱记得在 Java | 一分钟掌握异步编程 | 3 – 线程异步 – 掘金 (juejin.cn) 提到过,使用多线程实现异步的时候,创建线程池就是用的Executors创建的,这里创建一个任务类型的线程池,我们可以使用:
// mars酱
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool();
改写前面的例子
我们在前面使用Timer的时候遇到了阻塞,这次我们改用任务线程池来做,改一下前一篇的例子:
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
* @author mars酱
*/
public class MarsTimer {
public static void main(String[] args) {
// java.util.Timer timer = new Timer();
// timer.schedule(new TimerTask() {
// @Override
// public void run() {
// System.out.println("当前时间:" + new Date());
// }
// }, 1000, 5000);
// 1. 创建第一个任务,打印时间后延迟5秒
TimerTask tta = new TimerTask() {
@SneakyThrows
@Override
public void run() {
System.out.println(">> 这是a任务:当前时间:" + new Date());
Thread.sleep(5000);
}
};
// 2. 创建第二个任务,直接打印毫秒数
TimerTask ttb = new TimerTask() {
@Override
public void run() {
System.out.println("
改写之后,运行一下,得到的结果为:
好了,很工整,a和b两个任务都是独立在运行了,完美解决掉了共享队列导致阻塞的问题。
问题来了
如果Mars酱的任务是每个月执行一次,或者生日任务是每年执行一次,怎么办呐?
ScheduledExecutorService中的schedule函数虽然是支持周期单位到天的,但是如果是每周、每月、每年这种任务,我们在下次任务执行的时候,还要自行计算好时间才行,还是有点缺陷,解决办法也有:支持cron表达式就行。但是ScheduledExecutorService提供的方法是不支持cron表达式的。下面是cron表达是的介绍
cron表达式
cron表达式是一个具有时间含义的字符串,字符串以56个空格隔开,分为67个域,格式为X X X X X X X。其中X是一个域的占位符。最后一个代表年份的域非必须,可省略。单个域有多个取值时,使用半角逗号 , 隔开取值。每个域可以是确定的取值,也可以是具有逻辑意义的特殊字符。每个域最多支持一个前导零。比如:
0 10 01 ? * * 2023
表示2023年每天凌晨1点10分执行任务
域占位符的取值
下表为cron表达式中支持的特殊字符,以及含义:
域 |
是否必需 |
取值范围 |
特殊字符 |
秒 |
是 |
[0, 59] |
* , – / |
分钟 |
是 |
[0, 59] |
* , – / |
小时 |
是 |
[0, 23] |
* , – / |
日期 |
是 |
[1, 31] |
* , – / ? L W |
月份 |
是 |
[1, 12]或[JAN, DEC] |
* , – / |
星期 |
是 |
[1, 7]或[MON, SUN]。若您使用[1, 7]表达方式,1代表星期一,7代表星期日。 |
* , – / ? L # |
年 |
否 |
[当前年份,2099] |
* , – / |
特殊字符的含义
cron表达式中的每个域都支持一定数量的特殊字符,每个特殊字符有其特殊含义。
特殊字符 |
含义 |
示例 |
* |
所有可能的值。 |
在月域中,*表示每个月;在星期域中,*表示星期的每一天。 |
, |
列出枚举值。 |
在分钟域中,5,20表示分别在5分钟和20分钟触发一次。 |
– |
范围。 |
在分钟域中,5-20表示从5分钟到20分钟之间每隔一分钟触发一次。 |
/ |
指定数值的增量。 |
在分钟域中,0/15表示从第0分钟开始,每15分钟。在分钟域中3/20表示从第3分钟开始,每20分钟。 |
? |
不指定值,仅日期和星期域支持该字符。 |
当日期或星期域其中之一被指定了值以后,为了避免冲突,需要将另一个域的值设为?。 |
L |
单词Last的首字母,表示最后一天,仅日期和星期域支持该字符。 说明指定L字符时,避免指定列表或者范围,否则,会导致逻辑问题。 |
|
W |
除周末以外的有效工作日,在离指定日期的最近的有效工作日触发事件。W字符寻找最近有效工作日时不会跨过当前月份,连用字符LW时表示为指定月份的最后一个工作日。 |
在日期域中5W,如果5日是星期六,则将在最近的工作日星期五,即4日触发。如果5日是星期天,则将在最近的工作日星期一,即6日触发;如果5日在星期一到星期五中的一天,则就在5日触发。 |
# |
确定每个月第几个星期几,仅星期域支持该字符。 |
在星期域中,4#2表示某月的第二个星期四。 |
哪些定时任务支持cron表达式?
Linux操作系统支持cron表达式,Java支持cron表达式的有Spring框架。
到站下车了,下站见。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.e1idc.net