定时任务

来源:互联网 发布:知乎 方向盘套 编辑:程序博客网 时间:2024/05/22 14:12

    在java的开发中,在开发一个定时任务时,会采用Time,和TimeTask来组合处理;

    但是Timer和TimerTask存在一些缺陷:

1:Timer只创建了一个线程。当你的任务执行的时间超过设置的延时时间将会产生一些问题。

2:Timer创建的线程没有处理异常,因此一旦抛出非受检异常,该线程会立即终止。

      Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。

    Java提供的Time类可以周期性地或者延期执行任务,但是有时我们需要并行执行同样的任务,这个时候如果创建多个Time对象会给系统带来负担,解决办法是将定时任务放到线程池中执行。

     JDK 5.0以后推荐使用ScheduledThreadPoolExecutor,该类属于Executor Framework,它除了能处理异常外,还可以创建多个线程解决上面的问题。Java的ScheduledThreadPoolExecutor类实现了ScheduledExecutorService接口中定义的以不同方法执行任务的方法。

使用 Executors.newScheduledThreadPool的任务调度

     ScheduledExecutor

     鉴于 Timer 的上述缺陷,其设计思想是:每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。需要注意的是,只有当任务的执行时间到来时,ScheduedExecutor 才会真正启动一个线程,其余时间 ScheduledExecutor 都是在轮询任务的状态。

       其实现原理:ScheduledThreadPoolExecutor继承了ThreadPoolExecutor,它先把用户提交的任务进一步封装成ScheduledFutureTask。再把ScheduledFutureTask放到任务队列中,交给线程池的线程去执行。可以说ScheduledThreadPoolExecutor与ThreadPoolExecutor的最大区别就是多了一步封装ScheduledFutureTask的过程。其他像任务队列的执行,线程的管理等都于ThreadPoolExecutor差不多,甚至就是直接使用了ThreadPoolExecutor的方法。

    定时方法区别:

      1.schedule(commod,delay,unit) ,这个方法是说系统启动后,需要等待多久执行,delay是等待时间,只执行一次,没有周期性。比如炸弹的定时器,5,4,3,2,1,轰隆隆,发生爆炸,只发生一次。

      2.scheduleAtFixedRate(commod,initialDelay,period,unit),这个是以period为固定周期时间,按照一定频率来重复执行任务,initialDelay是说系统启动后,需要等待多久才开始执行。优先保证任务执行的频率,基于固定时间间隔进行任务调度。比如每个月5号,公司会发工资。

      3.scheduleWithFixedDelay(commod,initialDelay,delay,unit),这个是以delay为固定延迟时间,按照一定的等待时间来执行任务,initialDelay意义与上面的相同。即无论某个任务执行多长时间,等执行完了,我再延迟指定的时间,它受计划执行时间的影响。 优先保证任务执行的间隔,取决于每次任务执行的时间长短,是基于不固定时间间隔进行任务调度。比如我长途旅游,走了20分钟,休息10分钟,走了30分钟,休息10分钟,走了25分钟,休息了10分钟。。。。

    使用ScheduledThreadPoolExecutor时,必须注意以下几点:

      1. 一定要使用try{}catch(Throwable t){}捕获所有可能的异常,因为ScheduledThreadPoolExecutor会在任务执行遇到异常时取消后续执行。
      2. 注意scheduleAtFixedRate与scheduleWithFixedDelay的区别,scheduleAtFixedRate是上一个任务开始执行之后延迟设定时间再执行,是从上一个任务开始时计时,但对于运行时长超过延迟时长的任务,会等上一个任务执行完之后,下一个任务才开始执行,此时,延时没有任何意义。而scheduleWithFixedDelay是在上一个任务结束执行之后延迟设定时间再执行,是从上一个任务结束时开始计算。

      3.在执行延迟任务时,任务的执行不会早于你设定的延迟时间,但是也不保证恰好在达到你设定的延迟时间时就马上执行。在同一时间开始执行的任务,按照FIFO顺序提交给线程。
      4.虽然ScheduledThreadPoolExecutor继承了ThreadPoolExecutor。但是针对ThreadPoolExecutor的一些性能调优的方法不一定试用于ScheduledThreadPoolExecutor。在ThreadPoolExecutor中,调整corePoolSize,maximumPoolSize两个参数可以控制任务的执行速度,例如当前线程小于corePoolSize时,可以马上为新任务创建线程而不必等待,当前线程大于corePoolSize小于maximumPoolSize。可以动态扩展当前线程以提高并发速度等。但是对于ScheduledThreadPoolExecutor,它实际上是一个固定线程数,无界阻塞队列的线程池,所有任务都是先放到工作队列中,而不会有直接为其创建线程的优待。所以调整corePoolSize,maximumPoolSize对ScheduledThreadPoolExecutor来说,性能上不会有影响。