定时JOB,在什么时间进行执行代码任务。
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
count++;
System.out.println(count);
} catch (Exception e) {
// TODO: handle exception
}
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
public static void main(String[] args) {
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
count++;
System.out.println(count);
}
};
Timer timer = new Timer();
// 天数
long delay = 0;
// 秒数
long period = 1000;
timer.scheduleAtFixedRate(timerTask, delay, period);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
public void run() {
// task to run goes here
System.out.println("Hello !!");
}
};
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
// 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间
service.scheduleAtFixedRate(runnable, 1, 1, TimeUnit.SECONDS);
}
依赖:
org.quartz-scheduler
quartz
2.2.1
org.quartz-scheduler
quartz-jobs
2.2.1
任务:
public class JobTask implements Job {
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("quartz job date: "+new Date().getTime());
}
}
启动类:
public static void main(String[] args) throws SchedulerException {
//1、创建scheduler的工厂
StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
//2、从工厂中获取调度器实例
Scheduler scheduler = stdSchedulerFactory.getScheduler();
//3、创建JobDetail
JobDetail jobDetail = JobBuilder.newJob(JobTask.class)
.withDescription("this is a quartz job")
.withIdentity("quartzJob", "quartzGroup")
.build();
//任务运行的时间、simpleSchedule类型触发器有效
long time=System.currentTimeMillis()+5*1000;//5秒后
Date startTime=new Date(time);
//创建trigger
//使用SimpleScheduleBuilder或者CronScheduleBuilder
Trigger trigger = TriggerBuilder.newTrigger()
.withDescription("quartz trigger")
.withIdentity("quartzTrigger", "quartzTriggerGroup")
.startAt(startTime)
.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
.build();
//5、注册任务和定时器
scheduler.scheduleJob(jobDetail,trigger);
//启动
scheduler.start();
}
虽然以上是可以实现任务调度,但是一般情况下这个应用是要部署在多个tomcat服务器上的,那么又怎么保证幂等性(对于一个job,不可能每台服务器都让他执行一次嘛,这不就重复执行了吗)呢。
1、使用分布式锁,保证只有一台服务器在执行
2、添加配置文件标识,两台服务器的配置文件不同,根据配置文件不同进行任务的调度,缺点是,那这就不支持集群 了。
3、数据库唯一标识,比如根据某一字段为TRUE标识可以执行,执行时改为FALSE,执行完后再改为TRUE,缺点是经常操作数据库,效率低
4、使用分布式任务调度平台XXLJOB
总的来说传统的任务调度有很多缺点:
1、没有补偿机制(比如某个任务调度失败后,只能等待下次调度或者人工调度)
2、不支持集群
3、不支持路由策略
4、统计(每个服务或者项目都有自己的任务调度,肯定是要统计一些成功啊失败什么的,传统调度的话只能自己管理自己的,可是这种任务调度的话最好是采用集中管理比较好)
5、管理平台(没有提供一个集中管理所有任务调度的平台)
6、报警邮箱(比如说重试N次以后,都不成功那就发疯邮件吧)、状态监控(运行、结束、等待)
而以上这些在分布式调度平台XXLJOB都有支持。
首先对于任何一个客户端的任务,需要注册到xxl-job的admin平台,然后admin将任务分发到各个执行器去执行,这里选择每个执行器的原理类似负载均衡策略。
实战演练一下:
1、首先下载XXL-JOB
2、使用开发工具eclipse或者idea导入该项目
3、找到master/doc下的数据库文件导入数据库比如xx-job
4、修改配置文件xxl-job-admin.properties中数据库的链接地址和密码,这里如果有自己搭建邮箱服务器也可填写邮箱服务器等信息
5、将该项目部署到tomcat服务器进行启动,访问http://127.0.0.1:8081/,输入密码用户名(默认admin,123456)
6、在web页面中新建执行器以及任务
7、根据他提供的一些例子比如spring boot的,导入他的依赖以及配置文件这些信息到自己的项目中
8、填写好admin部署的项目地址,这点很重要,指定执行器名称、ip、端口、以及日志文件路径
9、记住XxlJobConfig这个配置文件一定要导入
10、新建一个Handler类似这样
/**
* 任务Handler的一个Demo(Bean模式)
*
* 开发步骤: 1、继承 “IJobHandler” ; 2、装配到Spring,例如加 “@Service” 注解; 3、加 “@JobHander”
* 注解,注解value值为新增任务生成的JobKey的值;多个JobKey用逗号分割; 4、执行日志:需要通过 "XxlJobLogger.log"
* 打印执行日志;
*
* @author xuxueli 2015-12-19 19:43:36
*/
@JobHander(value = "demoJobHandler")//这个对应admin中的对应执行器中的任务的名称
@Service
public class DemoJobHandler extends IJobHandler {
@Value("${xxl.job.executor.port}")
private String port;
@Override
public ReturnT execute(String... params) throws Exception {//任务执行的代码
XxlJobLogger.log("XXL-JOB, Hello World." + port);
System.out.println("XXL-JOB, Hello World." + port);
for (int i = 0; i < 5; i++) {
XxlJobLogger.log("beat at:" + i);
// TimeUnit.SECONDS.sleep(2);
}
return ReturnT.SUCCESS;
}
}
启动项目后即可。这个是一个分布式job调度平台,可以试着启动多个项目然后添加到同一个执行器中执行,按照他的规则填好集群中的ip即可。