实现Java动态启停定时任务

Java定时任务的原理

jdk自带的库中,有两种技术可以实现定时任务,一种是Timer,另一种是ScheduledThreadPoolExecutor

Timer+TimerTask

Timer是一个线程,控制执行TimerTask所需要执行的内容 

public class Timer {
    /**
     * The timer task queue.  This data structure is shared with the timer
     * thread.  The timer produces tasks, via its various schedule calls,
     * and the timer thread consumes, executing timer tasks as appropriate,
     * and removing them from the queue when they're obsolete.
     */
    private final TaskQueue queue = new TaskQueue();
    /**
     * The timer thread.
     */
    private final TimerThread thread = new TimerThread(queue);
    。。。。。。
}

 其中,需要注意,Timer类有几个方法创建不同的线程执行:

 延时执行

//其中的delay是延时时间,表示多少毫秒后执行一次task
public void schedule(TimerTask task, long delay) {
    if (delay < 0)
        throw new IllegalArgumentException("Negative delay.");
    sched(task, System.currentTimeMillis()+delay, 0);
}

指定时间点执行

//到达指定时间time的时候执行一次task
public void schedule(TimerTask task, Date time) {
    sched(task, time.getTime(), 0);
}

延时周期执行 

//经过delay毫秒后按每period毫秒执行一次的周期执行task
public void schedule(TimerTask task, long delay, long period) {
    if (delay < 0)
        throw new IllegalArgumentException("Negative delay.");
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, System.currentTimeMillis()+delay, -period);
}

作者:MrDong先生
链接:https://juejin.cn/post/7111992569034178574
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

指定时间点后周期执行

//到达指定时间firstTime之后按照每period毫秒执行一次的周期执行task
public void schedule(TimerTask task, Date firstTime, long period) {
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, firstTime.getTime(), -period);
}

TimerTask是一个实现了Runable接口的类,所以能够放到线程去执行:

public abstract class TimerTask implements Runnable {
    /**
     * This object is used to control access to the TimerTask internals.
     */
    final Object lock = new Object();
    
    。。。。。。
}

示例:

public class JavaTimerJob {
    public static void main(String[] args) {
        Timer timer = new Timer();
        Task task = new Task();
        //当前时间开始,每1秒执行一次
        timer.schedule(task, new Date(),1000);
    }
 }
class Task extends TimerTask {
    @Override
    public void run() {
        System.out.println(new Date()+":  This is my job...");
    }
}

 执行结果:

Wed Jul 6 03:45:47 CST 2022: This is my job...

Wed Jul 6 03:45:48 CST 2022: This is my job...

Wed Jul 6 03:45:49 CST 2022: This is my job...

Wed Jul 6 03:45:50 CST 2022: This is my job...

。。。。

弊端:Timer是单线程的,一旦定时任务中某一过程时刻抛出异常,将会导致整体线程停止,定时任务停止。 

ScheduledThreadPoolExecutor 

继承了 ThreadPoolExecutor, 是一个基于线程池的调度器 通过实现 ScheduledExecutorService 接口方法去实现任务调度,主要方法如下: 

延时执行

//command是待执行的线程,delay表示延时时长,unit代表时间单位
public ScheduledFuture<?> schedule(Runnable command,
                                   long delay,
                                   TimeUnit unit) {
    if (command == null || unit == null)
        throw new NullPointerException();
    RunnableScheduledFuture<?> t = decorateTask(command,
        new ScheduledFutureTask<Void>(command, null,
                                      triggerTime(delay, unit)));
    delayedExecute(t);
    return t;
}

延时周期执行

//command是待执行的线程,initialDelay表示延时时长,period代表执行间隔时长,unit代表时间单位
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                              long initialDelay,
                                              long period,
                                              TimeUnit unit) {
    if (command == null || unit == null)
        throw new NullPointerException();
    if (period <= 0)
        throw new IllegalArgumentException();
    ScheduledFutureTask<Void> sft =
        new ScheduledFutureTask<Void>(command,
                                      null,
                                      triggerTime(initialDelay, unit),
                                      unit.toNanos(period));
    RunnableScheduledFuture<Void> t = decorateTask(command, sft);
    sft.outerTask = t;
    delayedExecute(t);
    return t;
}

每段延时间隔执行

//command是待执行的线程,initialDelay表示延时时长,delay代表每次执行线程前的延时时长,unit代表时间单位
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                 long initialDelay,
                                                 long delay,
                                                 TimeUnit unit) {
    if (command == null || unit == null)
        throw new NullPointerException();
    if (delay <= 0)
        throw new IllegalArgumentException();
    ScheduledFutureTask<Void> sft =
        new ScheduledFutureTask<Void>(command,
                                      null,
                                      triggerTime(initialDelay, unit),
                                      unit.toNanos(-delay));
    RunnableScheduledFuture<Void> t = decorateTask(command, sft);
    sft.outerTask = t;
    delayedExecute(t);
    return t;
}

示例:

public class JavaScheduledThreadPoolExecutor {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(8);
        //延时1秒后开始执行,每3秒执行一次
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println(new Date()+": This is my job...");
            }
        }, 1, 3, TimeUnit.SECONDS);
    }
}

 执行结果:

Wed Jul 6 03:45:47 CST 2022: This is my job...

Wed Jul 6 03:45:48 CST 2022: This is my job...

Wed Jul 6 03:45:49 CST 2022: This is my job...

Wed Jul 6 03:45:50 CST 2022: This is my job...

。。。。

 Timer VS ScheduledThreadPoolExecutor

Timer

  • 是单线程,如果开启多个线程服务,将会出现竞争,一旦出现异常,线程停止,定时任务停止;
  • 兼容性更高,jdk1.3后使用

ScheduledThreadPoolExecutor

  • 基于线程池实现多线程,且自动调整线程数,线程出错并不会影响整体定时任务执行。
  • 在jdk1.5后可使用

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

雾里有果橙

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

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

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

打赏作者

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

抵扣说明:

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

余额充值