Java中 Timer缺陷,用ScheduledExecutorService替代

Java 并发专题 : Timer的缺陷 用ScheduledExecutorService替代 task2实际上是4后才执行,正因为Timer内部是一个线程,而任务1所需的时间超过了两个任务间的间隔导致。由于任务1的一次,任务2也停止运行了。以上是字节二面的一些问题,面完之后其实挺后悔的,没有提前把各个知识点都复习到位。MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理。MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理。MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理。,现在起闭关修炼半个月,争取早日上岸!2、Timer当任务抛出异常时的缺陷。 阅读详情

继续并发,上篇博客对于ScheduledThreadPoolExecutor没有进行介绍,说过会和Timer一直单独写一篇Blog.

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。

Win11下DCMTK的Visual Studio 2022配置教程 最近有个新需求,需要完成读取和解析DICOM数据相关的SDK 阅读详情

相关推荐

电压电流双闭环PFC单相PWM整流

电压电流双闭环PFC单相整流。仿真及代码

xht2403267701的博客 6051

通过ScheduledExecutorService代替Timer

用于记录一下 原来的代码是这样的: //定时器 Timer timer = new Timer(); TimerTask task = new TimerTask() { @Override public void run() { snake.move(); // 重绘棋盘 jPanel.repaint(); }

weixin_46063418的博客 2667

构建自己的哨兵数据集(以sentinel-1为例,使用SNAP软件)

通过欧洲航天官网获取哨兵数据的产品,通过SNAP软件进一步得到SAR图像(以导出图片为例)

xiaoxTai的博客 6182

使用ScheduledExecutorService替代timer

Timer不支持并发。 Timer不支持多线程。全部挂在Timer下的任务都是单线程的,任务仅仅能串行运行。假设当中一个任务运行时间过长。会影响到其它任务的运行,然后就可能会有各种接踵而来的问题。如果重开一个Timer?难道要为全部的耗时的Task都单开一个Timer。显然是不太可能。这样就太乱了。 Timer的线程不捕获异常。TimerTask假设抛出异常,那么Timer唯一的进程就会挂掉,这...

刘东阳的博客 5723

本地化部署dify,使用Database插件实现dify直连数据库报错No module named ‘MySQLdb‘解决方案

网上查阅各种资料,有说修改/dify-main/docker/volumes/sandbox/dependencies目录下的python-requirements.txt文件,添加了如下两行,试验后无效。,看到有人是其他报错,但是URI配置如下(在mysql后面加了pymysql),尝试后果真成功了。按照系统提示设置完数据库URI后保存出现错误。在工具市场查询Database,点击后进行授权。最后在该插件的项目地址获得灵感。

qiaoxu1989的博客 4333

SOLIDWORKS无法获得下列许可 无效的使用许可号码(-8,544,0) 解决办法大全

SOLIDWORKS无法获得下列许可 无效的使用许可号码(-8,544,0) 解决办法大全。版本:SolidWorks2021。电脑:惠普战66四代。软件安装不困难!

qq_43596278的博客 11万+

Java 并发专题 : Timer的缺陷 用ScheduledExecutorService替代

继续并发,上篇博客对于ScheduledThreadPoolExecutor没有进行介绍,说过会和Timer一直单独写一篇Blog. 1、Timer管理延时任务的缺陷 a、以前在项目中也经常使用定时器,比如每隔一段时间清理项目中的一些垃圾文件,每个一段时间进行数据清洗;然而Timer是存在一些缺陷的,因为Timer在执行定时任务时只会创建一个线程,所以如果存在多个任务,且任务时间过长,...

weixin_30906185的博客 1622

FMQL开发环境实战:从零构建国产FPGA SoC的软件基石

本文详细解析了构建国产复旦微FMQL FPGA SoC软件开发环境的完整流程。针对开发者在环境搭建中遇到的核心痛点,文章深入剖析了Procise、IAR与Vivado三大工具的协同角色与版本选择,提供了从软件下载、安装避坑到核心配置的实战指南,并总结了常见问题的排查方法,旨在帮助开发者高效跨过FMQL开发的“第一道坎”。

weixin_29215391的博客 125

【Java并发处理代码规范】之使用ScheduledExecutorService代替Timer进行定时任务并行处理

该规范指出在Java编程中,当需要多线程并行处理定时任务时,应使用。没有捕获抛出的异常,其他任务便会自动终止运行,而使用。进行多线程并行处理定时任务,使用。

wang2leee的博客 811

SpringBoot整合LangChain4j实现RAG检索实战详解

本文介绍了使用LangChain4j框架在Java生态中构建RAG(检索增强生成)应用的最佳实践。作为最接近Python LangChain的Java实现,LangChain4j提供了文档解析、向量化存储到检索增强的全套组件,并与SpringBoot深度集成。文章通过电商智能客服场景,详细演示了从零搭建RAG系统的完整流程:包括使用PostgreSQL+pgvector作为生产级向量数据库、文档加载与向量化处理、声明式AI服务实现以及查询压缩、结果重排等进阶优化技巧。同时对比了内存模式与生产级向量库的差异,

分享AI、区块链技术及应用,未来已来 432

【异常】Claude Code 在 Windows CMD 中出现重影现象的排查与解决

Windows CMD运行Claude Code时出现文字重影、乱码等问题,原因是传统CMD对现代ANSI终端控制序列支持不足。解决方案包括:1)推荐安装Windows Terminal(完全支持ANSI标准);2)使用PowerShell 7;3)优化CMD设置(启用虚拟终端、UTF-8编码);4)关闭Claude Code视觉特效。建议优先使用Windows Terminal以获得最佳体验,这是最彻底的解决方案。其他方案仅能部分改善或缓解问题。

奶爸的编程之路,也就一周冷个三天 1958

ScheduleExecutorService的使用(代替Tiemr定时器)

上一篇文章说过Timer的缺陷,并且要用ScheduledExecutorService代替Timer执行任务,这次就说一下使用一:简介    ScheduledExecutorService是ExecutorService接口的扩展schedule(Callable&lt;V&gt; callable, long delay, TimeUnit unit)创建并执行在给定延迟后启用的 Sched...

Fu_xl的博客 2013

Xilinx FPGA平台GTX简易使用教程(汇总篇)

Xilinx平台GTX简易使用教程,先“知其然”,慢慢再研究“所以然”。

数字IC/FPGA杂货铺,找一找,或许有你想要的~ 3万+

使用ScheduledExecutorService 替代Timer

大佬们,直接使用Timer 提示用ScheduledExecutorService 替代好点,麻烦看看下面写的一个工具类有没有毛病,忘大佬们不吝赐教 public class TimerUtil { private static TimerUtil instance; private final ScheduledExecutorService scheduledExecutorService; private TimerUtil() { Thre...

JianFeng_Z的博客 1484

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

java.util.concurrent之ScheduledExecutorService——替代Timer,实现多线程任务调度

ScheduledExecutorService来替代Timer主要原因例如以下: Timer不支持多线程。全部挂在Timer下的任务都是单线程的,任务仅仅能串行运行。假设当中一个任务运行时间过长。会影响到其它任务的运行,然后就可能会有各种接踵而来的问题。 Timer的线程不捕获异常。TimerTask假设抛出异常,那么Timer唯一的进程就会挂掉,这样挂在Timer下的全部任务都会无法继续运...

_夜渐凉 3031

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

使用 ScheduledExecutorService 来替换 Timer

ava.util.Timer计时器有管理任务延迟执行("如1000ms后执行任务")以及周期性执行("如每500ms执行一次该任务")。 但是,Timer存在一些缺陷: 1,Timer对调度的支持是基于绝对时间,而不是相对时间的,由此任务对系统时钟的改变是敏感的;ScheduledThreadExecutor只支持相对时间。  2,如果TimerTask抛出未检查的异常,Time

Mindy的专栏 1181

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

ScheduledExecutorService实现多线程任务调度,替代Timer

主要原因例如以下: Timer不支持多线程。全部挂在Timer下的任务都是单线程的,任务仅仅能串行运行。假设当中一个任务运行时间过长。会影响到其它任务的运行,然后就可能会有各种接踵而来的问题。 Timer的线程不捕获异常。TimerTask假设抛出异常,那么Timer唯一的进程就会挂掉,这样挂在Timer下的全部任务都会无法继续运行。 为了弥补Timer的缺陷,jdk1.5中引...

彦楠的博客 1240

谨慎使用 ScheduledExecutorService 执行周期性操作

问题 最近一个项目的程序需要安装到客户机器中(以服务方式),这个程序是Java 语言实现的。 这个程序大概做的事情就是每隔一段的时间从服务端拉取一些数据,经过一些计算之后再将结果发送到服务端。 然后此程序还包括一个每分钟发送一次的心跳,心跳是发送方式是HTTP GET,并且此GET 请求的报文是精简过的,使得每次心跳所发送的字节非常少。 本来这一切都很正常,不过在昨天我们做数据分析的时候发现有部分机器在掉线(一段时间没有发送心跳)复活之后会频繁发送心跳占用大量的带宽,这个频率完全超过了我们预设的每分钟一次。

Joel的博客 1792

java timer异常_JAVA Timer的缺陷以及解决办法

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

weixin_30336075的博客 4167

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

上篇博文《任务调度(三)——Timer的替代品ScheduledExecutorService简介》已经对ScheduledExecutorService做了简介。事实上使用ScheduledExecutorService来替代Timer也是迫不得已的事情。主要原因例如以下: Timer不支持多线程。全部挂在Timer下的任务都是单线程的,任务仅仅能串行运...

weixin_30670965的博客 302

ScheduledExecutorService的坑

使用的ScheduledExecutorService来定时执行任务,当有一个任务出现异常后就会卡住,不会继续执行后续的任务。所以如果样例代码中andonCallService.andonCall();抛出任何异常就会导致任务卡住。查看上面样例中使用的scheduleWithFixedDelay方法。查找定时运行的代码,捕获异常,当遇到错误时不影响后续任务执行。

dinghongyu520的博客 560

使用ScheduledExecutorService执行周期性任务需要注意的地方

使用spring框架开发程序时基本上很少有人会使用ScheduledExecutorService来执行周期性任务,但是ScheduledExecutorService在某些场景下可能会用到,使用JDK自带的这个周期性调度器时一定要确保任务内部不能抛出运行时异常,否则后续任务将不会执行,至于原因,接下来将从源码角度分析下: 使用Excutors工厂类创建的ScheduledExecutorSer...

johnhuster的专栏 1626
上一篇: Java String面试题
下一篇: C++ Socket通信总结(附C++实现)
cding1818
博客等级 码龄17年 963粉丝 154原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值