【Java实现定时任务有哪些方式?】

Java实现定时任务有哪些方式?

sleep

这也是我们最常用的sleep 休眠大法,不只是当作休眠用,我们还可以利用它很轻松的能实现一个简单的定时任务。

实现逻辑:

新开一个线程,添加一个 for/ while 死循环,然后在死循环里面添加一个sleep 休眠逻辑,让程序每隔N秒休眠再执行一次,这样就达到了一个简单定时任务的效果。

实现代码如下:
    private static void sleepTask() {
        new Thread(() -> {
            while (true) {
                System.out.println("你好");
                try {
                	//3秒执行一次
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        ).start();
    }

这种方式比较傻瓜化了,只能按固定频率运行,不能指定具体运行的时间。

Timer

JDK 1.3就内置了java.util.Timer类,可以用来调度java.util.TimerTask任务。

几个重要的方法:

  • schedule:开始调度任务,提供了几个包装方法
  • cancle:终止任务调度,取消当前调度的所有任务,正在运行的任务不受影响
  • purge:从任务队列中移除所有已取消的任务

另外, java.util. TimerTask就是实现了Runnable接口,具体任务逻辑则是在run方法里去实现。

具体方法实现如下

    public static void main(String[] args) {
        Timer timer = new Timer();
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("你好");
            }
        };
        //第一次任务延迟时间
        long delay = 3000L;
        //任务执行频率
        long period = 3 * 100;
        //开始调度
        timer.schedule(timerTask, delay, period);
        //指定首次运行时间
        //timer.schedule(timerTask, DateUtil.offsetDay(new Date(), 1), period);
        //终止并移除任务
        timer.cancel();
        timer.purge();
    }

这种实现方式比较简单,可以指定首次执行的延迟时间、首次执行的具体日期时间,以及执行频率,能满足日常需要。

另外,需要注意的是,Timer是线程安全的,因为背后是单线程在执行所有任务。

Timer 也会有一些缺陷:
  • Timer是单线程的,假如有任务A,B,C,任务A如果执行时间比较长,那么就会影响任务B,C的启动和执行时间,如果B,C执行时间也比较长,那就会相互影响;

  • Timer不会捕获异常,如果A,B,C任何一个任务在执行过程中发生异常,就会导致TImer整个定时任务停止工作;

  • Timer是基于绝对时间调度的,而不是基于相对时间,所以它对系统时间的改变非常敏感;

所以,如果在使用Timer的过程中要注意这些缺陷,虽然可以用,但不推荐。

ScheduledExecutorService

因Timer有一些缺陷,所以不太建议使用Timer,推荐使用ScheduledExecutorService:

ScheduledExecutorService 即是Timer的替代者,JDK1.5并发包引入,是基于线程池设计的定时任务类:

java.util.concurrent.Executors.newScheduledThreadPool
    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }

    public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1, threadFactory));
    }

上了线程池,每个调度任务都会分配到线程池中的某一个线程去执行,任务就是并发调度执行的,任务之间互不影响。

几个重要的调度方法:

  • schedule:只执行一次调度

  • scheduleAtFixedRate:按固定频率调度,如果执行时间过长,下一次调度会延迟,不会同时执行

  • scheduleWithFixedDelay:延迟调度,上一次执行完再加上延迟时间后执行

另外,可以看出,任务是支持Runnable和Callable 调度的。

public static void main(String[] args) {
		ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10);
		executorService.scheduleAtFixedRate(() ->{
			System.out.println("你好");
		},2000,3000, TimeUnit.MILLISECONDS);
	}

这是一个按固定频率调度的任务,创建了10个核心线程数,首次执行延迟2秒,后续每3秒执行一次。

这种方式简单、好用,避免了使用Timer 带来的各种问题,推荐使用这种实现方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

业余码手

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

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

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

打赏作者

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

抵扣说明:

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

余额充值