Tomcat使用shutdown.sh无法关闭Java进程的问题跟踪 问题: 在服务器上执行/usr/local/apache-tomcat-7.0.47-3100/bin/shutdown.sh后,使用 ps –aux|grep java 命令查看,发现java进程还存在,但是服务已经不可用了,即服务没有完全关闭。 跟踪过程: 1、 百度查找“Tomcat无法 shutdown进程”,得出原因为:有非守护线程存在的时候,JVM是不会退出的。 2、 查找shutdown.sh执行之后,有哪些非守护线程存在: 操作:1)执行shutdown.sh 2)使用jdk自带的jstack工具导出java进程中的线程堆栈: 使用ps –aux|grep java查看java进程pid(pid为一个整数); 使用jstack pid >/usr/local/threaddump.txt (该命令将所有线程堆栈导出到/usr/local/threaddump.txt文件中)。 3、 分析/usr/local/threaddump.txt中的线程堆栈,找到非守护线程,jvm的GC线程不用看。 可以使用UltraEidt编辑器辅助查找,搜索“prio=”,列出所有的线程,可以很容易的看到daemon字样的是守护线程,没有daemon字样的是非守护线程。 4、 本次跟踪的threaddump.txt只找到一个非守护线程的堆栈,如下: "pool-2-thread-1" prio=10 tid=0x00007f26244af000 nid=0xcb2 waiting on condition [0x00007f2616515000] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x00000000c2aedf98> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:196) 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:609) at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:602) 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:662) 5、 查找与该线程堆栈有关业务代码,经查,对应的代码为: //启动就运行,之后每12小时调用一次(默认) final int time = SystemInit.getSynLmpTime(); Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() { @Override public void run() { executeSynBrandData(); executeSynCategoryData(); executeSynStoreData(); executeDeleteByBeforeDays(SystemInit.getDeleteBeforeDays()); } }, 0, time, TimeUnit.HOURS); 修改方法: 外层代码要持有线程池的引用,以便shutdown时可以调用scheduledExecutorService.shutdown();进行关闭。 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() {
Tomcat使用shutdown.sh无法关闭Java进程的问题跟踪
问题:
在服务器上执行/usr/local/apache-tomcat-7.0.47-3100/bin/shutdown.sh后,使用
ps –aux|grep java 命令查看,发现java进程还存在,但是服务已经不可用了,即服务没有完全关闭。
跟踪过程:
1、 百度查找“Tomcat无法 shutdown进程”,得出原因为:有非守护线程存在的时候,JVM是不会退出的。
2、 查找shutdown.sh执行之后,有哪些非守护线程存在:
操作:1)执行shutdown.sh
2)使用jdk自带的jstack工具导出java进程中的线程堆栈:
使用ps –aux|grep java查看java进程pid(pid为一个整数);
使用jstack pid >/usr/local/threaddump.txt (该命令将所有线程堆栈导出到/usr/local/threaddump.txt文件中)。
3、 分析/usr/local/threaddump.txt中的线程堆栈,找到非守护线程,jvm的GC线程不用看。
可以使用UltraEidt编辑器辅助查找,搜索“prio=”,列出所有的线程,可以很容易的看到daemon字样的是守护线程,没有daemon字样的是非守护线程。
4、 本次跟踪的threaddump.txt只找到一个非守护线程的堆栈,如下:
"pool-2-thread-1" prio=10 tid=0x00007f26244af000 nid=0xcb2 waiting on condition [0x00007f2616515000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000c2aedf98> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:196)
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:609)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:602)
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:662)
5、 查找与该线程堆栈有关业务代码,经查,对应的代码为:
//启动就运行,之后每12小时调用一次(默认)
final int time = SystemInit.getSynLmpTime();
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
executeSynBrandData();
executeSynCategoryData();
executeSynStoreData();
executeDeleteByBeforeDays(SystemInit.getDeleteBeforeDays());
}
}, 0, time, TimeUnit.HOURS);
修改方法:
外层代码要持有线程池的引用,以便shutdown时可以调用scheduledExecutorService.shutdown();进行关闭。
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {