正在认真敲代码的楼主,突然收到数据维护系统发过来的报警邮件说楼主凌晨跑的定时任务没有成功,于是便开始了楼主今天的找坑填坑的过程。
贴个广告
楼主的博客已全部搬迁至自己的博客,感兴趣的小伙伴请移步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