Java中如何实现定时任务?

目录

一、定时任务

概念

作用

二、简单定时任务实现方式

1. Thread线程等待(最原始最简单方式)

2. 使用java.util.Timer

Timer 优缺点分析

3. 使用JDK自带的ScheduledExecutorService

 schedule和scheduleAtFixedRate的区别

schedule侧重保持间隔时间的稳定

scheduleAtFixedRate保持执行频率的稳定

4. 使用SpringTask实现定时任务

三、分布式定时任务实现方式

1. Quartz

示例:使用Quartz进行定时任务调度

Quartz的持久化

2. XXL-Job

3. Elastic-Job

比较

四、总结


一、定时任务

概念

定时任务是一种自动化执行特定操作的方式,可以根据预定的时间、日期或间隔周期性地执行某些任务。

在平常的生活中,大家肯定是有设置闹钟的习惯,我们需要通过闹钟来提醒我们到这个时刻,我们应该做指定的事情。同样的在编程当中,我们很多时候也是需要实现这样的操作的,到达指定的时刻,我们想要我们的程序去执行某一个事情,比如:指定时间发送邮箱、指定时间发送生日祝福……

以上的种种到达指定时间做指定事情,就是定时任务。

作用

  • 自动化任务执行:定时任务能够在预定的时间触发执行某些任务,无需人工干预。这对于需要定期执行的重复性任务非常有效,例如数据备份、统计报表生成、系统维护等。
  • 提高效率和准确性:通过定时任务,可以在特定的时间段内自动执行任务,避免了人工操作的疏忽和错误。这样可以提高任务的执行效率和准确性,并降低因人为原因导致的错误风险。
  • 节省时间和资源:定时任务可以代替人工手动执行的操作,节省了大量人力资源和时间成本。同时,它也可以合理分配系统资源,避免任务集中导致的系统负载过高。
  • 异步执行:定时任务可以在后台异步执行,不会阻塞用户的其他操作。这对于需要执行耗时较长的任务或需要长时间运行的操作非常有用,可以提高系统的响应速度和用户体验。

二、简单定时任务实现方式

今天我们来讨论一下在Java中如何实现定时任务。定时任务在很多场景下都非常有用,例如定期执行清理工作、数据备份、发送通知等。

在Java中,常见的可以实现定时任务的方式有如下几种:

(1)线程类实现定时任务:比如Thread、Runnable、Callable等线程类都可以实现定时任务。

(2)Timer/TimerTask:Java提供了java.util.Timer和java.util.TimerTask类,可以用于创建定时任务。通过创建一个Timer对象,并调用其schedule()方法,可以指定任务的执行时间和执行间隔。然后,创建一个继承自TimerTask的子类,实现具体的任务逻辑,并在run()方法中定义需要执行的代码。最后,将该任务对象通过Timer的schedule()方法进行调度即可。

(3)ScheduledExecutorService:Java提供了java.util.concurrent.ScheduledExecutorService接口,可以用于创建定时任务。通过调用ScheduledExecutorService的scheduleAtFixedRate()或scheduleWithFixedDelay()方法,可以指定任务的执行时间和执行间隔。然后,创建一个实现了Runnable接口的类,实现具体的任务逻辑,并在run()方法中定义需要执行的代码。最后,将该任务对象提交给ScheduledExecutorService进行调度即可。

(4)@Scheduled注解:这个是Spring框架所提供的,通过在方法上添加@Scheduled注解,并设置相应的时间表达式,就可以让方法按照指定的时间间隔自动执行。

1. Thread线程等待(最原始最简单方式)

创建一个thread,然后让它在while循环里一直运行着,通过sleep方法来达到定时任务的效果。

/**
 * 匿名内部类实现 java.lang.Runnable 接口
 */
public class ThreadTask {
    public static void main(String[] args) {
        final long timeInterval = 1000;
 
        //创建线程(匿名内部类方式)
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
                    String dateStr = sdf.format(new Date());
                    System.out.println("线程等待实现定时任务:" + dateStr);
 
                    try {
                        Thread.sleep(timeInterval);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        //开启线程
        thread.start();
    }
}
public class ThreadTask1 {
    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        //创建线程(自定义类MyRunnable实现java.lang.Runnable接口)
        Thread t = new Thread(runnable);
        //开启线程
        t.start();
    }
}
 
/**
 * 自定义类MyRunnable实现java.lang.Runnable接口
 */
class MyRunnable implements Runnable{
    final long timeInterval = 1000;
 
    @Override
    public void run() {
        while (true){
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
            String dateStr = sdf.format(new Date());
            System.out.println("线程等待实现定时任务1:" + dateStr);
 
            try {
                Thread.sleep(timeInterval);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2. 使用java.util.Timer

JDK自带的Timer API算是最古老的定时任务实现方式了。Timer是一种定时器工具,使用java.util.Timer工具类。用来在一个后台线程计划执行指定任务。它可以安排任务“执行一次”或者定期“执行多次”。

Timer类核心方法如下:

// 在指定延迟时间后执行指定的任务
schedule(TimerTask task,long delay);
 
// 在指定时间执行指定的任务。(只执行一次)
schedule(TimerTask task, Date time);
 
// 延迟指定时间(delay)之后,开始以指定的间隔(period)重复执行指定的任务
schedule(TimerTask task,long delay,long period);
 
// 在指定的时间开始按照指定的间隔(period)重复执行指定的任务
schedule(TimerTask task, Date firstTime , long period);
 
// 在指定的时间开始进行重复的固定速率执行任务
scheduleAtFixedRate(TimerTask task,Date firstTime,long period);
 
// 在指定的延迟后开始进行重复的固定速率执行任务
scheduleAtFixedRate(TimerTask task,long delay,long period);
 
// 终止此计时器,丢弃所有当前已安排的任务。
cancal();
 
// 从此计时器的任务队列中移除所有已取消的任务。
purge();
 
import java.util.Timer;
import java.util.TimerTask;

public class TimerExample {
    public static void main(String[] args) {
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("Task executed at: " + System.currentTimeMillis());
            }
        };
        
        Timer timer = new Timer();
        // 安排任务在1秒后执行,并且每隔1秒执行一次
        timer.scheduleAtFixedRate(task, 1000, 1000);
    }
}

在这个示例中,我们创建了一个Timer对象,并用scheduleAtFixedRate方法安排一个TimerTask在1秒后开始执行,并且每隔1秒执行一次。

Timer 优缺点分析

优点:JDK自带的,简单易用。

缺点:

(1)对系统时间敏感

Timer类的任务调度是基于绝对时间的,而不是相对时间,所以它对系统时间的改变非常敏感。当系统时间发生变化时,可能导致任务执行时间的误差。

(2)不适合高并发场景

由于Timer类使用单个线程执行所有任务,不适合在高并发环境下使用。当任务过多或任务执行时间较长时,会影响整体性能和响应性。

(3)任务的无法持久化

当应用程序关闭或重启时,Timer 中已经调度的任务会丢失。

(4)单线程执行

Timer类内部使用单个线程来执行所有的定时任务。如果某个任务执行时间过长,会影响其他任务的执行,可能导致任务被延迟。

当一个任务的执行时间过长时,会影响其他任务的调度。

import java.text.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值