Timer的缺陷 用ScheduledExecutorService替代
GIT: https://github.com/whtchl/JavaConcurrentTemplate
继续并发,上篇博客对于ScheduledThreadPoolExecutor没有进行介绍,说过会和Timer一直单独写一篇Blog.
1、Timer管理延时任务的缺陷
a、以前在项目中也经常使用定时器,比如每隔一段时间清理项目中的一些垃圾文件,每个一段时间进行数据清洗;然而Timer是存在一些缺陷的,因为Timer在执行定时任务时只会创建一个线程,所以如果存在多个任务,且任务时间过长,超过了两个任务的间隔时间,会发生一些缺陷:下面看例子:
Timer的源码:
- 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 TaskQueue queue = new TaskQueue();
- /**
- * The timer thread.
- */
- private TimerThread thread = new TimerThread(queue);
TimerThread是Thread的子类,可以看出内部只有一个线程。下面看个例子:
- package com.zhy.concurrency.timer;
- import java.util.Timer;
- import java.util.TimerTask;
- public class TimerTest
- {
- private static long start;
- public static void main(String[] args) throws Exception
- {
- TimerTask task1 = new TimerTask()
- {
- @Override
- public void run()
- {
- System.out.println("task1 invoked ! "
- + (System.currentTimeMillis() - start));
- try
- {
- Thread.sleep(3000);
- } catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- }
- };
- TimerTask task2 = new TimerTask()
- {
- @Override
- public void run()
- {
- System.out.println("task2 invoked ! "
- + (System.currentTimeMillis() - start));
- }
- };
- Timer timer = new Timer();
- start = System.currentTimeMillis();
- timer.schedule(task1, 1000);
- timer.schedule(task2, 3000);
- }
- }
定义了两个任务,预计是第一个任务1s后执行,第二个任务3s后执行,但是看运行结果:
- task1 invoked ! 1000
- task2 invoked ! 4000
task2实际上是4后才执行,正因为Timer内部是一个线程,而任务1所需的时间超过了两个任务间的间隔导致。下面使用ScheduledThreadPool解决这个问题:
- package com.zhy.concurrency.timer;
- import java.util.TimerTask;
- import java.util.concurrent.Executors;
- import java.util.concurrent.ScheduledExecutorService;
- import java.util.concurrent.TimeUnit;
- public class ScheduledThreadPoolExecutorTest
- {
- private static long start;
- public static void main(String[] args)
- {
- /**
- * 使用工厂方法初始化一个ScheduledThreadPool
- */
- ScheduledExecutorService newScheduledThreadPool = Executors
- .newScheduledThreadPool(2);
- TimerTask task1 = new TimerTask()
- {
- @Override
- public void run()
- {
- try
- {
- System.out.println("task1 invoked ! "
- + (System.currentTimeMillis() - start));
- Thread.sleep(3000);
- } catch (Exception e)
- {
- e.printStackTrace();
- }
- }
- };
- TimerTask task2 = new TimerTask()
- {
- @Override
- public void run()
- {
- System.out.println("task2 invoked ! "
- + (System.currentTimeMillis() - start));
- }
- };
- start = System.currentTimeMillis();
- newScheduledThreadPool.schedule(task1, 1000, TimeUnit.MILLISECONDS);
- newScheduledThreadPool.schedule(task2, 3000, TimeUnit.MILLISECONDS);
- }
- }
输出结果:
- task1 invoked ! 1001
- task2 invoked ! 3001
符合我们的预期结果。因为ScheduledThreadPool内部是个线程池,所以可以支持多个任务并发执行。
2、Timer当任务抛出异常时的缺陷
如果TimerTask抛出RuntimeException,Timer会停止所有任务的运行:
- package com.zhy.concurrency.timer;
- import java.util.Date;
- import java.util.Timer;
- import java.util.TimerTask;
- public class ScheduledThreadPoolDemo01
- {
- public static void main(String[] args) throws InterruptedException
- {
- final TimerTask task1 = new TimerTask()
- {
- @Override
- public void run()
- {
- throw new RuntimeException();
- }
- };
- final TimerTask task2 = new TimerTask()
- {
- @Override
- public void run()
- {
- System.out.println("task2 invoked!");
- }
- };
- Timer timer = new Timer();
- timer.schedule(task1, 100);
- timer.scheduleAtFixedRate(task2, new Date(), 1000);
- }
- }
上面有两个任务,任务1抛出一个运行时的异常,任务2周期性的执行某个操作,输出结果:
- task2 invoked!
- Exception in thread "Timer-0" java.lang.RuntimeException
- at com.zhy.concurrency.timer.ScheduledThreadPoolDemo01$1.run(ScheduledThreadPoolDemo01.java:24)
- at java.util.TimerThread.mainLoop(Timer.java:512)
- at java.util.TimerThread.run(Timer.java:462)
由于任务1的一次,任务2也停止运行了。。。下面使用ScheduledExecutorService解决这个问题:
- package com.zhy.concurrency.timer;
- import java.util.Date;
- import java.util.Timer;
- import java.util.TimerTask;
- import java.util.concurrent.Executors;
- import java.util.concurrent.ScheduledExecutorService;
- import java.util.concurrent.TimeUnit;
- public class ScheduledThreadPoolDemo01
- {
- public static void main(String[] args) throws InterruptedException
- {
- final TimerTask task1 = new TimerTask()
- {
- @Override
- public void run()
- {
- throw new RuntimeException();
- }
- };
- final TimerTask task2 = new TimerTask()
- {
- @Override
- public void run()
- {
- System.out.println("task2 invoked!");
- }
- };
- ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
- pool.schedule(task1, 100, TimeUnit.MILLISECONDS);
- pool.scheduleAtFixedRate(task2, 0 , 1000, TimeUnit.MILLISECONDS);
- }
- }
代码基本一致,但是ScheduledExecutorService可以保证,task1出现异常时,不影响task2的运行:
- task2 invoked!
- task2 invoked!
- task2 invoked!
- task2 invoked!
- task2 invoked!<span style="font-family: Arial, Helvetica, sans-serif;">...</span>
3、Timer执行周期任务时依赖系统时间
Timer执行周期任务时依赖系统时间,如果当前系统时间发生变化会出现一些执行上的变化,ScheduledExecutorService基于时间的延迟,不会由于系统时间的改变发生执行变化。
上述,基本说明了在以后的开发中尽可能使用ScheduledExecutorService(JDK1.5以后)替代Timer。
Timer的缺陷 用ScheduledExecutorService替代相关推荐
- 使用Timer的缺陷
2019独角兽企业重金招聘Python工程师标准>>> Java.util.Timer定时器实际上是一个单线程,实际调度所拥有的TimerTask任务. 1.时间的不准确性 如果存在 ...
- Java SE加强篇——超详细,Java入门,这一篇就够了
建议先阅读 JavaSE基础篇 第一天:面向对象进阶一 一.static静态 关键字 1.static是什么? static是静态的意思,可以修饰成员变量和成员方法 static修饰成员变量表示该成员 ...
- day16多线程网络编程日志枚举
多线程&网络编程 一.实现多线程 1.1 相关概念 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的一条执行路径.实际运作单位.简单理解:应用软件中互相独立,可以同时运 ...
- java捕获定时器抛出的异常_详细了解Java中定时器Timer的使用及缺陷分析
在需要定时并且周期执行任务时,在最初的JAVA工具类库中,Timer可以实现任务的定时周期执行的需求,不过有一定的缺陷,比如,Timer是基于绝对时间而非相对时间,因此Timer对系统时钟比较敏感,本 ...
- java一定时间间隔的定时任务_Java 定时任务---Timer
本文来自我一个朋友的个人博客(希望各位以后多多支持):https://www.liupeng.mobi/archives/777 一.Timer类 在java中一个完整的定时任务需要由Timer和Ti ...
- 为什么你不该用Timer
概述 在Java开发中,用过定时功能的同学一定不会对Timer感到陌生.不过,除了Timer,在Java 5之后又引入了一个定时工具ScheduledThreadPoolExecutor,那么我们应该 ...
- 【Java定时任务调度工具】Timer
笔记来源:IMOOC Java Timer 定时任务调度 基于给定的时间点,给定的时间间隔或者给定的执行次数自动执行的任务. Timer 定义 一种工具,线程用其安排以后在后台线程中执行的任务.可安排 ...
- 缺陷预防-我认为的质量改进正道之光
欢迎关注公众号"软件质量奇谈".关于软件工程,测试,质量管理等问题,欢迎在公众号留言提问,必定尽力解答,如有资料需求,也可尽力分享. 前段时间在和几位研发团队负责人讨论团队的质量目 ...
- 【慕课笔记】Java定时任务调度工具详解之Timer篇_0理论
慕课地址 1 简单介绍 1)什么是定时任务调度 2)Timer简介 打开jdk-zh说明文档查看即可 推荐看英文版本的 简单写个demo,感受一下timer的定时调度函数.schedule()(本人实 ...
最新文章
- ECS服务器指定实例规格最佳推荐
- linux 守护进程管理 supervisor 简介 可用于docker容器内守护进程
- PHP获取当前时间、时间戳的各种格式写法汇总[日期时间]
- mysql修改字符集utf8为utf8mb4
- 超基础的Android studio的安装教程
- linux 安装软件
- 技术分享 | 一文带你了解测试流程体系
- i.mx6 linux 占用率,i.MX6UL在Linux和Windows平台下SD启动卡测试步骤
- 黑客X档案的《黑客免杀入门》
- linux 上传下载测速
- 《不只是美:信息图表设计原理与经典案例》—— 2.7 更加灵活
- 快速给图片加水印的方法
- 基于大型数字视频监控系统解决方案
- 【Python】把excel文件中的数据转化为字典格式存起来
- 嵌入式系统python开发_嵌组词_嵌的拼音含义_组词造句解释_嵌字的组词
- VR/AR年度创投报告
- 帮你学会webpack
- solidity部署和验证代理合约
- php单独使用laravel数据库 | laravel手动关闭数据库连接
- TrueNAS安装(虚拟机环境)
热门文章
- php 模板使用,在PHP中使用模板的方法
- C++知识点21——使用C++标准库(再谈string——string的搜索和数值转化)
- 本质矩阵与基本矩阵(对极几何)
- skipping non-radio button in group解决方法
- AprilTag中的g3d.h和g2d.c文件
- python提供两个对象身份比较操作符什么和什么来测试_python - 第二部分
- jmeter操作数据库
- 因缺失log4j.properties 配置文件导致flume无法正常启动。
- ApiCloud云端管理平台(v.20151022)
- FZU 2159 WuYou