摘自:https://www.cnblogs.com/Howlet/p/15580411.html
还没真正的遇到使用定时任务的场景,不管怎么说先学起来
很多情况下任务并非需要立即执行,而是需要往后或定期执行,这不可能人工去操作,所以定时任务就出现了。项目中肯定会用到使用定时任务的情况,笔者就需要定时去拉取埋点数据
使用定时任务的情况:
笔试中首次遇到定时任务急急忙忙想出来的方法
public class ThreadSchedule { public static void main(String[] args) { // 5 秒后执行任务 int interval = 1000 * 5; // 新线程执行 new Thread(() -> { try { Thread.sleep(interval); System.out.println("执行定时任务"); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } }
Timer 负责执行计划功能,会启动一个后台线程,而 TimerTask 负责任务逻辑
public class TimeSchedule { public static void main(String[] args) { // 启动一个守护线程 Timer timer = new Timer(); // 定时任务 TimerTask timerTask = new TimerTask() { @Override public void run() { System.out.println("执行定时任务"); } }; long delay = 0; // 延迟执行 long period = 1000 * 5; // 间隔 timer.scheduleAtFixedRate(timerTask, 1, period); // timer.cancel(); 可取消 } }
// new Timer() 最终的构造函数会启动一个线程 public Timer(String name) { thread.setName(name); thread.start(); } // 这个线程里面封装了一个 Queue 优先级队列,该线程会去队列里不停执行里面的任务 class TimerThread extends Thread { private TaskQueue queue; TimerThread(TaskQueue queue) { this.queue = queue; } } // 这个队列里面存放了各种 TimerTask 定时的任务逻辑 class TaskQueue { private TimerTask[] queue = new TimerTask[128]; }
java.util.concurrent中的工具类,是一个多线程的定时器
public class ExecutorSchedule { public static void main(String[] args) { // 定时任务 Runnable runnable = new Runnable() { @Override public void run() { System.out.println("执行定时任务"); } }; // 线程池执行 long delay = 0; // 延迟执行 long period = 1000 * 5; // 间隔 ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); service.scheduleAtFixedRate(runnable, delay, period, TimeUnit.MILLISECONDS); }
笔者最常用的一个定时操作了,之前还写过定时的探测任务
需要开启定时功能@EnableScheduling
@Component public class SpringSchedule { // cron 表达式,每秒执行一次 @Scheduled(cron = "*/1 * * * * ?") public void springSchedule(){ System.out.println("执行定时任务"); } }
底层是 ScheduledThreadPoolExecutor 线程池,和上面的 ScheduledExecutorService 是同根同源
xxl-job 是个人维护的分布式任务调度框架(国人写的,有详细的中文文档),分为 调度中心 和 执行器。执行器就是定时任务,而调度中心则负责管理调用这些定时任务,调度中心也可以存储定时任务通过脚本形式(Java 是 Grovvy)免编译地实时下发到各服务中执行。最重要的是有 UI 界面,用户友好的体验
xxl-job 的存储是基于数据库的,相对比 quartz 可保存在内存和数据库有一点性能影响。首先第一步就是要建库,在 xxl-job 官网有 SQL 语句 tables_xxl_job.sql,直接执行即可建库建表
从 Git 上拉取最新的代码,然后编译根模块,填好 admin 模块的数据库地址等,即可启动这个调度中心(支持 Docker 部署,更加方便)
在需要定时任务的服务中 引入依赖、添加配置、创建定时任务
<!-- xxl-job-core --> <dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>${project.parent.version}</version> </dependency>
# xxl-job admin address xxl.job.admin.addresses=http://xxx.xxx.xxx:8080/xxl-job-admin # xxl-job executor appname xxl.job.executor.appname=xxl-job-executor-demo
@Component public class MyJob { @XxlJob("MyJob") public void MyJob() throws Exception { // 执行器日志记录 XxlJobHelper.log("myjob is execute"); // 定时任务逻辑 System.out.println("myjob is executing"); // default success } }
进入调度中心新建一个任务,然后执行定时任务即可(使用的是 RPC 远程过程调用)
默认执行器是自动注册到调度中心的,但是时常进去的地址有问题而导致执行失败,所以要手动录入执行器的地址
作为轻量级的分布式定时任务,有 UI 界面简单方便使用,而且对代码没什么侵入性,已经能满足大部分项目的需求了,笔者如果要用定时任务也会首选 xxl-job