可以直接用spring的定时任务,看这里https://www.cnblogs.com/zjdxr-up/p/7778135.html
定时任务触发的时间改为3秒执行一次
@Scheduled(cron = "0/2 * * * * ?") //每隔5秒执行一次定时任务
public void consoleInfo(){
System.out.println("定时任务");
}
在consoleInfo的方法体里面添加你上面读取txtd的文本,再掉调用redis的方法。把List 放到redis中,.
redis整合spring 看这里https://blog.csdn.net/qq_33556185/article/details/79774908
用redis完成类似 at 命令的功能,例如订单24小时后没有支付自动关闭,定时发邮件,主要说下任务生成之后怎么触发消费。
使用 有序集合
思路: 使用sorted Sets的自动排序, key 为任务id,score 为任务计划执行的时间戳,这样任务在加入sets的时候已经按时间排序,这样每隔1s(或者其他间隔)去取出sets顶部的数据,小于当前时间的可以通过pop取出来然后去执行。
redis模拟
127.0.0.1:6379> zadd cron 10001 task1
(integer) 1
127.0.0.1:6379> zadd cron 9001 task2
(integer) 1
127.0.0.1:6379> zadd cron 29001 task3
(integer) 1
127.0.0.1:6379> ZRANGE cron 0 -1 withscores
1) "task2"
2) "9001"
3) "task1"
4) "10001"
5) "task3"
6) "29001"
假设当前的时间戳是 15000
127.0.0.1:6379> ZRANGEBYSCORE cron -inf 15000
1) "task2"
2) "task1"
127.0.0.1:6379> ZREM cron task2
(integer) 1
127.0.0.1:6379> ZREM cron task1
(integer) 1
127.0.0.1:6379> ZRANGE cron 0 -1 withscores
1) "task3"
2) "29001"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
上面的测试直接把小于当前时间戳的所有任务都做了一遍,会有些bug,例如找个定时监测程序挂了2天, 对于某些任务可能有效期只有那么10分钟,重新启动定时监测程序,就会把过期任务也做了一遍, 那么我们选取任务的时候范围要更精确一些。
如果当前时间戳是 29100 可以取到 task3
127.0.0.1:6379> ZRANGEBYSCORE cron 28500 29100
1) "task3"
如果当前时间戳是 30600 就无法取到 task3, 注意对过期任务的清理
127.0.0.1:6379> ZRANGEBYSCORE cron 30000 30600
(empty list or set)
1
2
3
4
5
6
7
利用键过期通知
思路: reids 2.8 有一种 键空间通知的机制 Keyspace Notifications (强烈推荐看一遍), 允许客户端去订阅一些key的事件,其中就有 key过期的事件,我们可以把 key名称设置为 task的id等标识(这种方式value的值无法取到,所以只用key来识别任务),expire设置为计划要执行的时间,然后开启一个客户端来订阅消息过期事件,然后处理task。
需要更改redis配置,注意版本要在2.8.0以上, 如果没有这个key 请添加上,如果有请更改为下面这样
notify-keyspace-events Ex
1
重启redis,第一个窗口, 开启订阅
liuzhizhi@lzz-rmbp|redis_test # redis-cli --csv psubscribe '__keyevent@0__:expired'
Reading messages... (press Ctrl-C to quit)
"psubscribe","__keyevent@0__:expired",1
"pmessage","__keyevent@0__:expired","__keyevent@0__:expired","task1"
"pmessage","__keyevent@0__:expired","__keyevent@0__:expired","task2"
1
2
3
4
5
第二个窗口 设置key
127.0.0.1:6379> set task1 xx
OK
127.0.0.1:6379> EXPIRE task1 5
(integer) 1
127.0.0.1:6379> set task2 xx
OK
127.0.0.1:6379> EXPIREAT task2 1469525560
(integer) 1
1
2
3
4
5
6
7
8
当key过期的时候就看到第一个窗口的通知了,订阅的key keyevent@:expired 这个格式是固定的,db代表的是数据库的编号,由于订阅开启之后这个库的所有key过期时间都会被推送过来,所以最好单独使用一个数据库来进行隔离。
小结
作者:orangleliu
来源:CSDN
原文:https://blog.csdn.net/orangleliu/article/details/52038092
版权声明:本文为博主原创文章,转载请附上博文链接!
https://blog.csdn.net/u012832579/article/details/82660571 看看我的博客
1、你可以使用java中提供的Timer
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println("hello world!");
}
}, 0, 3000);
2、你可以使用带有调度的线程池
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(() -> {
System.out.println("hello world!");
}, 0, 3, TimeUnit.SECONDS);
3、你可以使用上面几位同学spring提供的定时任务
3.1 使用注解
@Component
public class JobTask {
// http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/support/CronSequenceGenerator.html
// @Scheduled(cron = "* * * * * *")
// 每天的早上9点42分执行一次
@Scheduled(cron = "0 42 9 * * *")
public void job() {
System.out.println("++++++++++++++++++++++++++");
System.out.println(new Date());
}
}
<!-- 定时任务 -->
<task:annotation-driven />
Date sequence generator for a Crontab pattern, allowing clients to specify a pattern that the sequence matches.
The pattern is a list of six single space-separated fields: representing second, minute, hour, day, month, weekday. Month and weekday names can be given as the first three letters of the English names.
Example patterns:
* "0 0 * * * *" = the top of every hour of every day.
* "*/10 * * * * *" = every ten seconds.
* "0 0 8-10 * * *" = 8, 9 and 10 o'clock of every day.
* "0 0/30 8-10 * * *" = 8:00, 8:30, 9:00, 9:30 and 10 o'clock every day.
* "0 0 9-17 * * MON-FRI" = on the hour nine-to-five weekdays
* "0 0 0 25 12 ?" = every Christmas Day at midnight
3.2 直接使用配置文件
<!-- 启用spring定时任务 -->
<task:annotation-driven scheduler="youScheduler"/>
<task:scheduler id="youScheduler" pool-size="1"/>
<task:scheduled-tasks>
<task:scheduled ref="task" method="cronInvoke" cron="0/3 * * * * ?"/>
</task:scheduled-tasks>
<task:executor id="executor" pool-size="10" keep-alive="30" queue-capacity="20480" rejection-policy="ABORT"/>
4、使用第三方的工具cron4j
public class Main {
public static void main(String[] args) {
if (args.length != 1) {
System.out.println("仅需要一个日志文件的路径");
return;
}
final File logFile = new File(args[0]);
if (!logFile.exists()) {
try {
boolean flag = logFile.createNewFile();
if (!flag) {
System.out.print("日志文件无法创建!");
}
} catch (IOException e) {
e.printStackTrace();
}
}
Scheduler s = new Scheduler();
// 20:03分启动一下
s.schedule("03 20 * * *", new Runnable() {
public void run() {
try {
String log = new Date().toString();
Files.append(log, logFile, Charset.defaultCharset());
} catch (IOException e) {
e.printStackTrace();
}
// do something
}
});
s.start();
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
}
s.stop();
}
}
定时任务本身来说是一个很常见的事情,对于和数据处理下游项目,定时任务可能会存在几十个甚至更多。上面的集中做法只适用于单机定时任务,对于分布式的项目来说定时任务就需要单独的集中式任务调度平台处理了。
鉴于你的demo性质,就不要使用spring的定时任务了,建议使用带有调度能力的线程池,这和你的需求比较契合。