点真背,上班第一天就遇到个奇怪的问题。
1、现象:
应用执行完毕之后,不能正常退出。
jstack发现多了下面这个非daemon线程。
"pool-1-thread-1" prio=10 tid=0x00007f8131439800 nid=0x2922 waiting on condition [0x00007f804b6a5000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00007f80a1773f08> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2025)
at java.util.concurrent.DelayQueue.take(DelayQueue.java:164)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:583)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:576)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:947)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:619)
2、分析
因为应用的前一版本在线上执行没有问题,线下修改的内容也基本不会造成问题,所以查了一下。
3、过程
真tm坑爹,线程的名字丝毫没有帮助。
开始google的时候,有人说是jdk的bug,也有人说是死锁。结果都不是。
没办法,硬着头皮,一点一点把依赖的jar包降回去。
n次编译之后,发现是某个jar包的问题。出问题的代码类似于这个:
public static void main(String[] args) {
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
executor.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println(new Date());
}
}, 1000L, 1000L, TimeUnit.MILLISECONDS);
}
4、解决办法
找到那个jar包的负责人确认了,下个版本发布掉。
5、结论
5.1、线程的名字太飘逸的话,问题真难找。
5.2、点真背,别再让我遇到这样的bug了吧。
5.3、我真有耐心。编译了整个下午!