JDK 定时任务 Timer 与 ScheduledExecutorService 排坑记录

本文记录了作者在使用JDK的Timer和ScheduledExecutorService进行定时任务时遇到的问题及解决方案。Timer的问题在于任务抛出未检查异常会导致线程终止,而ScheduledExecutorService能更好地处理异常。作者的定时任务因ScheduledExecutorService中的任务异常而未执行,通过查看日志和源码定位到问题,并修改代码以确保异常时任务仍能继续执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

正在认真敲代码的楼主,突然收到数据维护系统发过来的报警邮件说楼主凌晨跑的定时任务没有成功,于是便开始了楼主今天的找坑填坑的过程。

贴个广告

楼主的博客已全部搬迁至自己的博客,感兴趣的小伙伴请移步haifeiWu与他朋友们的博客专栏

定时任务,关于 Timer 与 ScheduledExecutorService 的抉择

这事肯定会有小伙伴说了为啥不用Quartz啊,因为楼主的庙小啊,就几个定时任务而已Quartz太重了。

Timer 存在的问题

Timer的主要问题在于,如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。Timer线程并不捕获异常,所以TimerTask抛出的未检查的异常会终止timer线程,这种情况下,Timer也不会再重新恢复线程的执行了;它错误的认为整个Timer都被取消了。此时,已经被安排但尚未执行的TimerTask永远不会再执行了,新的任务也不能被调度了。

使用 ScheduledExecutorService

ScheduledExecutorService 是 JDK 1.5之后 concurrent 包下提供的 API 。ScheduledExecutorService 妥善地处理了这个异常的任务,所以说在 JDK1.5 或更高的 JDK 中,楼主不建议使用Timer。关于 ScheduledExecutorService 楼主的另一篇文章也有提到,感兴趣的小伙伴请移步Java实现终止线程池中正在运行的定时任务

产生的问题

上面说了一堆 Timer 与 ScheduledExecutorService 的区别,有点不着重点,现在重点来了,楼主凌晨的定时任务没有跑成功就是使用了 ScheduledExecutorService 而不是 Timer ,当然倘若使用了Timer而导致的问题楼主也没必要说了。下面开始我们的找坑过程

查日志

通过 JDK 提供的 jstack 工具获取服务的 jstack 日志,如下所示:


2018-07-18 15:39:09
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.79-b02 mixed mode):

"Attach Listener" daemon prio=10 tid=0x00007f5bd0007800 nid=0x4e78 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"DestroyJavaVM" prio=10 tid=0x00007f5bec008800 nid=0x1dd5 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Thread-4" prio=10 tid=0x00007f5bec4be000 nid=0x1df8 runnable [0x00007f5be88b2000]
   java.lang.Thread.State: RUNNABLE
    at java.net.PlainDatagramSocketImpl.receive0(Native Method)
    - locked <0x00000000e7e450b8> (a java.net.PlainDatagramSocketImpl)
    at java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:146)
    - locked <0x00000000e7e450b8> (a java.net.PlainDatagramSocketImpl)
    at java.net.DatagramSocket.receive(DatagramSocket.java:816)
    - locked <0x00000000e7e450e8> (a java.net.DatagramPacket)
    - locked <0x00000000e7e45110> (a java.net.DatagramSocket)
    at com.yg84.chelaile.middleware.common.remotedata.protocol.udp.UDPReceiver$1.run(UDPReceiver.java:55)
    at java.lang.Thread.run(Thread.java:745)

"pool-5-thread-1" prio=10 tid=0x00007f5bec4ba800 nid=0x1df6 waiting on condition [0x00007f5be89b3000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000e7f1e510> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
    at java.util.concurrent
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值