Timer的缺陷 用ScheduledExecutorService替代

转自:  http://blog.csdn.net/lmj623565791/article/details/27109467

1、Timer管理延时任务的缺陷

a、以前在项目中也经常使用定时器,比如每隔一段时间清理项目中的一些垃圾文件,每个一段时间进行数据清洗;然而Timer是存在一些缺陷的,因为Timer在执行定时任务时只会创建一个线程,所以如果存在多个任务,且任务时间过长,超过了两个任务的间隔时间,会发生一些缺陷:下面看例子:

Timer的源码:

[java] view
plain
copy

  1. public class Timer {  
  2.     /** 
  3.      * The timer task queue.  This data structure is shared with the timer 
  4.      * thread.  The timer produces tasks, via its various schedule calls, 
  5.      * and the timer thread consumes, executing timer tasks as appropriate, 
  6.      * and removing them from the queue when they're obsolete. 
  7.      */  
  8.     private TaskQueue queue = new TaskQueue();  
  9.   
  10.     /** 
  11.      * The timer thread. 
  12.      */  
  13.     private TimerThread thread = new TimerThread(queue);  

TimerThread是Thread的子类,可以看出内部只有一个线程。下面看个例子:

[java] view
plain
copy

  1. package com.zhy.concurrency.timer;  
  2.   
  3. import java.util.Timer;  
  4. import java.util.TimerTask;  
  5.   
  6. public class TimerTest  
  7. {  
  8.     private static long start;  
  9.   
  10.     public static void main(String[] args) throws Exception  
  11.     {  
  12.   
  13.         TimerTask task1 = new TimerTask()  
  14.         {  
  15.             @Override  
  16.             public void run()  
  17.             {  
  18.   
  19.                 System.out.println("task1 invoked ! "  
  20.                         + (System.currentTimeMillis() - start));  
  21.                 try  
  22.                 {  
  23.                     Thread.sleep(3000);  
  24.                 } catch (InterruptedException e)  
  25.                 {  
  26.                     e.printStackTrace();  
  27.                 }  
  28.   
  29.             }  
  30.         };  
  31.         TimerTask task2 = new TimerTask()  
  32.         {  
  33.             @Override  
  34.             public void run()  
  35.             {  
  36.                 System.out.println("task2 invoked ! "  
  37.                         + (System.currentTimeMillis() - start));  
  38.             }  
  39.         };  
  40.         Timer timer = new Timer();  
  41.         start = System.currentTimeMillis();  
  42.         timer.schedule(task1, 1000);  
  43.         timer.schedule(task2, 3000);  
  44.   
  45.     }  
  46. }  

定义了两个任务,预计是第一个任务1s后执行,第二个任务3s后执行,但是看运行结果:

[java] view
plain
copy

  1. task1 invoked ! 1000  
  2. task2 invoked ! 4000  

task2实际上是4后才执行,正因为Timer内部是一个线程,而任务1所需的时间超过了两个任务间的间隔导致。下面使用ScheduledThreadPool解决这个问题:

[java] view
plain
copy

  1. package com.zhy.concurrency.timer;  
  2.   
  3. import java.util.TimerTask;  
  4. import java.util.concurrent.Executors;  
  5. import java.util.concurrent.ScheduledExecutorService;  
  6. import java.util.concurrent.TimeUnit;  
  7.   
  8. public class ScheduledThreadPoolExecutorTest  
  9. {  
  10.     private static long start;  
  11.   
  12.     public static void main(String[] args)  
  13.     {  
  14.         /** 
  15.          * 使用工厂方法初始化一个ScheduledThreadPool 
  16.          */  
  17.         ScheduledExecutorService newScheduledThreadPool = Executors  
  18.                 .newScheduledThreadPool(2);  
  19.           
  20.         TimerTask task1 = new TimerTask()  
  21.         {  
  22.             @Override  
  23.             public void run()  
  24.             {  
  25.                 try  
  26.                 {  
  27.   
  28.                     System.out.println("task1 invoked ! "  
  29.                             + (System.currentTimeMillis() - start));  
  30.                     Thread.sleep(3000);  
  31.                 } catch (Exception e)  
  32.                 {  
  33.                     e.printStackTrace();  
  34.                 }  
  35.   
  36.             }  
  37.         };  
  38.   
  39.         TimerTask task2 = new TimerTask()  
  40.         {  
  41.             @Override  
  42.             public void run()  
  43.             {  
  44.                 System.out.println("task2 invoked ! "  
  45.                         + (System.currentTimeMillis() - start));  
  46.             }  
  47.         };  
  48.         start = System.currentTimeMillis();  
  49.         newScheduledThreadPool.schedule(task1, 1000, TimeUnit.MILLISECONDS);  
  50.         newScheduledThreadPool.schedule(task2, 3000, TimeUnit.MILLISECONDS);  
  51.     }  
  52. }  

输出结果:

[java] view
plain
copy

  1. task1 invoked ! 1001  
  2. task2 invoked ! 3001  

符合我们的预期结果。因为ScheduledThreadPool内部是个线程池,所以可以支持多个任务并发执行。

2、Timer当任务抛出异常时的缺陷

如果TimerTask抛出RuntimeException,Timer会停止所有任务的运行:

[java] view
plain
copy

  1. package com.zhy.concurrency.timer;  
  2.   
  3. import java.util.Date;  
  4. import java.util.Timer;  
  5. import java.util.TimerTask;  
  6.   
  7.   
  8. public class ScheduledThreadPoolDemo01  
  9. {  
  10.   
  11.   
  12.     public static void main(String[] args) throws InterruptedException  
  13.     {  
  14.   
  15.         final TimerTask task1 = new TimerTask()  
  16.         {  
  17.   
  18.             @Override  
  19.             public void run()  
  20.             {  
  21.                 throw new RuntimeException();  
  22.             }  
  23.         };  
  24.   
  25.         final TimerTask task2 = new TimerTask()  
  26.         {  
  27.   
  28.             @Override  
  29.             public void run()  
  30.             {  
  31.                 System.out.println("task2 invoked!");  
  32.             }  
  33.         };  
  34.           
  35.         Timer timer = new Timer();  
  36.         timer.schedule(task1, 100);  
  37.         timer.scheduleAtFixedRate(task2, new Date(), 1000);  
  38.           
  39.           
  40.   
  41.     }  
  42. }  

上面有两个任务,任务1抛出一个运行时的异常,任务2周期性的执行某个操作,输出结果:

[java] view
plain
copy

  1. task2 invoked!  
  2. Exception in thread "Timer-0" java.lang.RuntimeException  
  3.     at com.zhy.concurrency.timer.ScheduledThreadPoolDemo01$1.run(ScheduledThreadPoolDemo01.java:24)  
  4.     at java.util.TimerThread.mainLoop(Timer.java:512)  
  5.     at java.util.TimerThread.run(Timer.java:462)  

由于任务1的一次,任务2也停止运行了。。。下面使用ScheduledExecutorService解决这个问题:

[java] view
plain
copy

  1. package com.zhy.concurrency.timer;  
  2.   
  3. import java.util.Date;  
  4. import java.util.Timer;  
  5. import java.util.TimerTask;  
  6. import java.util.concurrent.Executors;  
  7. import java.util.concurrent.ScheduledExecutorService;  
  8. import java.util.concurrent.TimeUnit;  
  9.   
  10.   
  11. public class ScheduledThreadPoolDemo01  
  12. {  
  13.   
  14.   
  15.     public static void main(String[] args) throws InterruptedException  
  16.     {  
  17.   
  18.         final TimerTask task1 = new TimerTask()  
  19.         {  
  20.   
  21.             @Override  
  22.             public void run()  
  23.             {  
  24.                 throw new RuntimeException();  
  25.             }  
  26.         };  
  27.   
  28.         final TimerTask task2 = new TimerTask()  
  29.         {  
  30.   
  31.             @Override  
  32.             public void run()  
  33.             {  
  34.                 System.out.println("task2 invoked!");  
  35.             }  
  36.         };  
  37.           
  38.           
  39.           
  40.         ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);  
  41.         pool.schedule(task1, 100, TimeUnit.MILLISECONDS);  
  42.         pool.scheduleAtFixedRate(task2, 0 , 1000, TimeUnit.MILLISECONDS);  
  43.   
  44.     }  
  45. }  

代码基本一致,但是ScheduledExecutorService可以保证,task1出现异常时,不影响task2的运行:

[java] view
plain
copy

  1. task2 invoked!  
  2. task2 invoked!  
  3. task2 invoked!  
  4. task2 invoked!  
  5. task2 invoked!<span style="font-family: Arial, Helvetica, sans-serif;">...</span>  

3、Timer执行周期任务时依赖系统时间

Timer执行周期任务时依赖系统时间,如果当前系统时间发生变化会出现一些执行上的变化,ScheduledExecutorService基于时间的延迟,不会由于系统时间的改变发生执行变化。

上述,基本说明了在以后的开发中尽可能使用ScheduledExecutorService(JDK1.5以后)替代Timer。

好了,如果博客中存在错误,请留言指出~

时间: 2024-08-02 21:37:37

Timer的缺陷 用ScheduledExecutorService替代的相关文章

任务调度(四)——ScheduledExecutorService替代Timer,实现多线程任务调度

       上篇博文<任务调度(三)--Timer的替代品ScheduledExecutorService简介>已经对ScheduledExecutorService做了简单介绍,其实使用ScheduledExecutorService来替代Timer也是迫不得已的事情.主要原因如下: Timer不支持多线程,所有挂在Timer下的任务都是单线程的,任务只能串行执行,如果其中一个任务执行时间过长,会影响到其他任务的执行,然后就可能会有各种接踵而来的问题. Timer的线程不捕获异常,Time

TIMER定时任务求救

问题描述 现在有一需求,第一个定时任务就是打开第二个定时任务,第二个定时任务我是用的TIMER来写的,第一个定时任务用的quartz配置,现在quartz配置晚上12点执行,这个定时任务的作用就是打开第二个定时任务,Timer写的定时任务,TIMER这个定时任务要实现的就是从数据库库的某张表中取出一个字段叫"执行时间",意思就是查出来要执行的时间,然后想让TIMER在"执行时间"到的时候去动态的执行timertask.前面的都做好了,但是取出"执行时间&q

解析Java中的定时器及使用定时器制作弹弹球游戏的示例_java

  在我们编程过程中如果需要执行一些简单的定时任务,无须做复杂的控制,我们可以考虑使用JDK中的Timer定时任务来实现.下面LZ就其原理.实例以及Timer缺陷三个方面来解析java Timer定时器. 一.简介      在java中一个完整定时任务需要由Timer.TimerTask两个类来配合完成. API中是这样定义他们的,Timer:一种工具,线程用其安排以后在后台线程中执行的任务.可安排任务执行一次,或者定期重复执行.由TimerTask:Timer 安排为一次执行或重复执行的任务

详解java定时任务_java

 在我们编程过程中如果需要执行一些简单的定时任务,无须做复杂的控制,我们可以考虑使用JDK中的Timer定时任务来实现.下面LZ就其原理.实例以及Timer缺陷三个方面来解析java Timer定时器. 一.简介      在java中一个完整定时任务需要由Timer.TimerTask两个类来配合完成. API中是这样定义他们的,Timer:一种工具,线程用其安排以后在后台线程中执行的任务.可安排任务执行一次,或者定期重复执行.由TimerTask:Timer 安排为一次执行或重复执行的任务.

Android性能优化以及数据优化方法_Android

Android性能优化-布局优化 今天,继续Android性能优化 一 编码细节优化. 编码细节,对于程序的运行效率也是有很多的影响的.今天这篇主题由于技术能力有限,所以也不敢在深层去和大家分享.我将这篇主题分为以下几个小节: (1)缓存 (2)数据 (3)延迟加载和优先加载 1> 缓存 在Android中缓存可以用在很多的地方:对象.IO.网络.DB等等..对象缓存能减少内存分配,IO缓存能对磁盘的读写访问,网络缓存能减少对网络的访问,DB缓存能减少对数据库的操作. 缓存针对的场景在Andro

Android性能优化以及数据优化方法

Android性能优化-布局优化 今天,继续Android性能优化 一 编码细节优化. 编码细节,对于程序的运行效率也是有很多的影响的.今天这篇主题由于技术能力有限,所以也不敢在深层去和大家分享.我将这篇主题分为以下几个小节: (1)缓存 (2)数据 (3)延迟加载和优先加载 1> 缓存 在Android中缓存可以用在很多的地方:对象.IO.网络.DB等等..对象缓存能减少内存分配,IO缓存能对磁盘的读写访问,网络缓存能减少对网络的访问,DB缓存能减少对数据库的操作. 缓存针对的场景在Andro

Java多线程知识小抄集(一)

本文主要整理博主遇到的Java多线程的相关知识点,适合速记,故命名为"小抄集".本文没有特别重点,每一项针对一个多线程知识做一个概要性总结,也有一些会带一点例子,习题方便理解和记忆. 1. interrupted与isInterrupted的区别 interrupted():测试当前线程是否已经是中断状态,执行后具有状态标志清除为false的功能. isInterrupted():测试线程Thread对象是否已经是中断状态,但不清除状态标志. 方法: public static boo

ScheduledExecutorService和timer的异同

先来个传统的Timer的例子: [java] view plaincopy package com.jerry.concurrency;      import java.text.ParseException;   import java.text.SimpleDateFormat;   import java.util.Date;   import java.util.Timer;   import java.util.TimerTask;      public class Traditi

任务调度(三)——Timer的替代品ScheduledExecutorService简介

       先前的两篇博文<任务调度(一)--jdk自带的Timer>和<任务调度(二)--jdk自带的Timer 动态修改任务执行计划>中,简单介绍了一下Timer,可以实现几本的功能,但是在多线程方面却略显不足.        根据Timer源码,可以看到Timer是单线程的.所以task都是串行执行.假如其中一个task执行需要很长的时间,那其他的task只能干巴巴的等着.怎么办!       现在就遇到了这样的问题.总不能因为这个小小的问题就去换别的任务调度框架吧,还是想