1.问题调查分析
发现在代码中使用了线程池 Executors.newFixedThreadPool(20);
我们先不讨论此处线程池使用是否正确,仅就此处修改而言,将原有 Executors.newFixedThreadPool() 替换;似乎并无不妥(这么修改,是为了遵循阿里规约)
int nThreads = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor pools = new ThreadPoolExecutor(nThreads, nThreads, 120L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(),
new ThreadFactoryBuilder().setNameFormat("receive-from-python-thread-pool-%d").build(),
new ThreadPoolExecutor.AbortPolicy());
1.1 dump线程分析
查找到Java程序对应的进程号
jps -l
将对应Java程序的线程栈信息转储到thread_dump.log文件
jstack ${pid_num} > thread_dump.log
"pool-165671-thread-1" #188938 prio=5 os_prio=0 tid=0x00007f1a38040000 nid=0x7f19 waiting on condition [0x00007f19065b9000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000dbb0a178> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"pool-164990-thread-1" #188175 prio=5 os_prio=0 tid=0x00007f1a5402c800 nid=0x7a61 waiting on condition [0x00007f18d0d5e000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000d8c1ef78> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
原因:程序每次调用方法时,均会创建一个新的线程池来执行任务。但在执行任务后并未关闭该线程池,造成线程无法被回收,线程一直处于等待状态。因而线程数会随时间线性上升
2.总结
这个问题是由于线程池使用不当造成的。使用线程池是为了避免重复、频繁地创建、销毁线程,进而对多个线程进行复用。以上线程池的使用明显未达到该目的,并因为线程池未关闭而造成线程无法被回收,线程数持续增加。

本文详细介绍了在Linux系统中遇到Java应用程序线程数异常时的排查步骤,包括如何使用JDK工具(如jstack)进行线程 dump,分析线程状态,找出可能导致问题的原因,以及结合Linux命令(如ps, top, strace等)进一步定位问题。"
81516263,7770296,Tomcat启动错误:数据库连接超时问题及解决,"['数据库连接', 'Tomcat故障排查', 'MySQL管理', '服务器维护']
1576

被折叠的 条评论
为什么被折叠?



