1. 程式人生 > >tomcat shudown.sh 無法關閉

tomcat shudown.sh 無法關閉

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() {