java scheduledexecutor 每小时_Java定时线程池_ScheduledExecutorService原理分析

在上一章中,我们详细讲解线程池的作用,它可以在新的线程中执行任务,而且高效快捷,因为不用频繁地创建和销毁线程。

但是我们经常碰到这样的需求,任务不是立即执行,而是经过一段时间之后,才会执行。或者任务可以循环周期性地执行。那么怎么实现这样的需求呢?

在java中提供了ScheduledExecutorService接口,那么实现上面的需求。

一. ScheduledExecutorService接口

public interface ScheduledExecutorService extends ExecutorService {

// 给定的延迟时间delay之后,才会执行任务command

public ScheduledFuture> schedule(Runnable command,

long delay, TimeUnit unit);

// 给定的延迟时间delay之后,才会执行任务callable

public ScheduledFuture schedule(Callable callable,

long delay, TimeUnit unit);

/**

* 在给定的初始化延时initialDelay之后,固定频率地周期性执行任务command。

* 也就是说任务第一次运行时间是initialDelay,第二次运行时间是initialDelay+period,

* 第三次是initialDelay + period*2等等。 所以频率是相同地。

*

* 但是有一个问题,如果任务运行时间大于周期时间period该怎么办?

* 其实是这样的,在initialDelay之后开始运行任务,当任务完成之后,

* 将当前时间与initialDelay+period时间进行比较,如果小于initialDelay+period时间,那么等待,

* 如果大于initialDelay+period时间,那么就直接执行第二次任务

*

*/

public ScheduledFuture> scheduleAtFixedRate(Runnable command,

long initialDelay,

long period,

TimeUnit unit);

/**

* 在给定的初始化延时initialDelay之后,开始执行任务,任务执行完成之后,

* 等待delay时间,再一次执行任务。

* 因为它是等待任务完成之后,再进行延迟,就不会受任务完成时间长短地影响。

*/

public ScheduledFuture> scheduleWithFixedDelay(Runnable command,

long initialDelay,

long delay,

TimeUnit unit);

}

ScheduledExecutorService接口定义了四个方法:

schedule的两个方法,延时delay时间后执行任务。区别Callable参数可以获取任务完成的结果值,Runnable参数的不会得到结果值。

scheduleAtFixedRate方法:在延时initialDelay时间之后,开始第一次执行任务,然后每隔周期时间period,再次执行任务。注意如果任务消耗时间大于周期时间period,会等待任务完成之后,才再次执行任务。

scheduleWithFixedDelay方法:在延时initialDelay时间之后,开始第一次执行任务,任务执行完成之后,再延时delay时间,然后再次执行任务。

下面我们结合例子来说明。

二. 延迟执行任务

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.ThreadFactory;

import java.util.concurrent.TimeUnit;

class MyRun implements Runnable {

private long start;

public MyRun() {

this.start = System.currentTimeMillis();

}

@Override

public void run() {

long time = System.currentTimeMillis() - start;

System.out.println("--"+Thread.currentThread().getName()+"开始运行 time=="+time);

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

System.out.println(Thread.currentThread().getName()+" 发生中断异常 exception=="+e.getMessage());

}

time = System.currentTimeMillis() - start;

System.out.println("======="+Thread.currentThread().getName()+"结束 time=="+time);

}

}

class MThreadFactory implements ThreadFactory {

private int sequenceNumber = 0;

@Override

public Thread newThread(Runnable r) {

return new Thread(r, "线程"+(++sequenceNumber));

}

}

public class ScheduledExecutorServiceTest {

public static void main(String[] args) {

ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(new MThreadFactory());

MyRun run = new MyRun();

service.schedule(run, 1000, TimeUnit.MILLISECONDS);

}

}

运行结果:

--线程1开始运行 time==1004

=======线程1结束 time==2006

可以看出任务run的确延时了1秒之后才执行的。

三. 周期性执行任务

3.1 scheduleAtFixedRate方法

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.ThreadFactory;

import java.util.concurrent.TimeUnit;

class MyRun implements Runnable {

private long start;

public MyRun() {

this.start = System.currentTimeMillis();

}

@Override

public void run() {

long time = System.currentTimeMillis() - start;

System.out.println("--"+Thread.currentThread().getName()+"开始运行 time=="+time);

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

System.out.println(Thread.currentThread().getName()+" 发生中断异常 exception=="+e.getMessage());

}

time = System.currentTimeMillis() - start;

System.out.println("======="+Thread.currentThread().getName()+"结束 time=="+time);

}

}

class MThreadFactory implements ThreadFactory {

private int sequenceNumber = 0;

@Override

public Thread newThread(Runnable r) {

return new Thread(r, "线程"+(++sequenceNumber));

}

}

public class ScheduledExecutorServiceTest {

public static void main(String[] args) {

ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(new MThreadFactory());

MyRun run = new MyRun();

service.scheduleAtFixedRate(run, 0, 2000, TimeUnit.MILLISECONDS);

}

}

运行结果:

--线程1开始运行 time==1

=======线程1结束 time==1005

--线程1开始运行 time==2005

=======线程1结束 time==3009

--线程1开始运行 time==4003

=======线程1结束 time==5007

--线程1开始运行 time==6002

=======线程1结束 time==7007

--线程1开始运行 time==8004

=======线程1结束 time==9005

--线程1开始运行 time==10004

=======线程1结束 time==11008

调用了scheduleAtFixedRate方法,设置周期时间是2000毫秒,发现任务run的确是每隔2000毫秒执行一次。那是因为我们任务消耗时间是1000毫秒,小于周期时间。如果我们将周期时间改为500毫秒会出现什么情况?

运行结果:

--线程1开始运行 time==1

=======线程1结束 time==1005

--线程1开始运行 time==1006

=======线程1结束 time==2011

--线程1开始运行 time==2011

=======线程1结束 time==3015

--线程1开始运行 time==3015

=======线程1结束 time==4019

--线程1开始运行 time==4019

=======线程1结束 time==5023

--线程1开始运行 time==5024

=======线程1结束 time==6028

--线程1开始运行 time==6028

=======线程1结束 time==7032

我们发现任务run并不是每隔周期时间500毫秒执行一次,而是每隔任务完成时间1000毫秒执行一次.

所以对于scheduleAtFixedRate方法来说:

如果执行完任务后,发现时间没有到定时的周期时间,那么就会等待,直到时间到了再执行任务。

如果执行完任务后,发现时间超过定时的周期时间,那么就直接再次执行任务。

3.2 scheduleWithFixedDelay方法

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.ThreadFactory;

import java.util.concurrent.TimeUnit;

class MyRun implements Runnable {

private long start;

public MyRun() {

this.start = System.currentTimeMillis();

}

@Override

public void run() {

long time = System.currentTimeMillis() - start;

System.out.println("--"+Thread.currentThread().getName()+"开始运行 time=="+time);

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

System.out.println(Thread.currentThread().getName()+" 发生中断异常 exception=="+e.getMessage());

}

time = System.currentTimeMillis() - start;

System.out.println("======="+Thread.currentThread().getName()+"结束 time=="+time);

}

}

class MThreadFactory implements ThreadFactory {

private int sequenceNumber = 0;

@Override

public Thread newThread(Runnable r) {

return new Thread(r, "线程"+(++sequenceNumber));

}

}

public class ScheduledExecutorServiceTest {

public static void main(String[] args) {

ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(new MThreadFactory());

MyRun run = new MyRun();

service.scheduleWithFixedDelay(run, 0, 500, TimeUnit.MILLISECONDS);

}

}

运行结果:

--线程1开始运行 time==1

=======线程1结束 time==1004

--线程1开始运行 time==1509

=======线程1结束 time==2513

--线程1开始运行 time==3013

=======线程1结束 time==4016

--线程1开始运行 time==4519

=======线程1结束 time==5524

--线程1开始运行 time==6028

=======线程1结束 time==7029

--线程1开始运行 time==7531

=======线程1结束 time==8535

--线程1开始运行 time==9040

=======线程1结束 time==10044

scheduleWithFixedDelay方法的意义就是当任务完成之后,延迟delay时间,再一次执行任务,一直循环下去。

总结

ScheduledExecutorService接口中的方法已经详细举例分析了,如果你只是想使用定时线程池的话,那么你已经知道该如何使用了。但是如果你想知道定时线程池是怎么实现的话,请看我的下一篇文章。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值