首页 > 工作 > JavaApplication进程不自动结束

JavaApplication进程不自动结束

今天发现线上一台服务器上一个用crontab周期性执行的Java Application同时存在多个进程。
细查了一下,发现相应的任务执行完成后,进程未终止。
因为代码中有大量线程的使用,怀疑是有用户线程(非守护线程)在运行。
遍历了一下,把所有的new Thread后都加上或改成置为守护线程:

                Thread thread = new Thread(r);
                thread.setDaemon(true);

关于thread.setDaemon的说明如下,大意是当前所有的线程都是守护线程时,进程结束。

void java.lang.Thread.setDaemon(boolean on)

Marks this thread as either a daemon thread or a user thread. The Java Virtual Machine exits when the only threads running are all daemon threads. 

This method must be called before the thread is started. 

This method first calls the checkAccess method of this thread with no arguments. This may result in throwing a SecurityException (in the current thread). 

Parameters:
on if true, marks this thread as a daemon thread.
Throws:
IllegalThreadStateException - if this thread is active.
SecurityException - if the current thread cannot modify this thread.
See Also:
isDaemon()
checkAccess

改完后测试,问题依旧。

先搞了个简单粗暴的方式,在main方法最后加一行结束代码

System.exit(0);

问题解决,不过原因不知道。

继续挖了一下,找到一些眉目。
使用jstack 进程id,查到所有线程的栈信息和状态,大部分为daemon,筛选了一下非deamon的线程,发现一个非daemon的很可疑

jstack 1463 > stack.log
grep prio stack.log | grep -v daemon
"DestroyJavaVM" prio=10 tid=0x0000000040111800 nid=0x5b9 waiting on condition [0x0000000000000000]
"pool-11-thread-1" prio=10 tid=0x00002aaab4669000 nid=0x5f6 waiting on condition [0x0000000041e46000]
"Timer-2" prio=10 tid=0x00002aaab4281000 nid=0x5f5 in Object.wait() [0x0000000041d45000]
"VM Thread" prio=10 tid=0x00002aaaafb6e800 nid=0x5c2 runnable 
"GC task thread#0 (ParallelGC)" prio=10 tid=0x0000000040124800 nid=0x5be runnable 
"GC task thread#1 (ParallelGC)" prio=10 tid=0x0000000040126800 nid=0x5bf runnable 
"GC task thread#2 (ParallelGC)" prio=10 tid=0x0000000040128000 nid=0x5c0 runnable 
"GC task thread#3 (ParallelGC)" prio=10 tid=0x000000004012a000 nid=0x5c1 runnable 
"VM Periodic Task Thread" prio=10 tid=0x00002aaaafbae000 nid=0x5cc waiting on condition 

其中pool-11-thread-1看起来不像是VM的,看期完整栈信息及状态

"pool-11-thread-1" prio=10 tid=0x00002aaab4669000 nid=0x5f6 waiting on condition [0x0000000041e46000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at xx.xxx.Xxx$1.run(Xxx.java:33)
        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
        at java.lang.Thread.run(Thread.java:662)

看了一下对应的代码实现,弄明白原因了

        Executors.newSingleThreadExecutor().execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    ....
                }
            }
        });

Executors.newSingleThreadExecutor()用的是默认的ThreadFactory,创建的都是非daemon的线程,用自己定义的ThreadFactory后正常

        ThreadFactory threadFac = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setDaemon(true);
                return thread;
            }
        };
        Executors.newSingleThreadExecutor(threadFac).execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    ....
                }
            }
        });

一个小插曲:中间曾经想在run方法内改线程的daemon状态

        Executors.newSingleThreadExecutor().execute(new Runnable() {
             @Override
            public void run() {
                Thread.currentThread().setDaemon(true); 
                while (true) {
                    ....
                }
            }
        });

出异常后才想起来setDaemon的说明:This method must be called before the thread is started.

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.