java.exe没有结束 - 只剩下一个OS线程

时间:2015-03-19 11:25:27

标签: java multithreading terminate

调度程序启动一个java应用程序,它在大多数情况下都没有任何问题。

然而,有时java.exe进程并没有结束。 到目前为止我们可以看到,java应用程序本身已经结束,但java.exe进程没有。 没有解决方案,但要杀死它。

Process Explorer仅显示此进程的一个线程(在OS的意义上,而不是java)。这就是国家"等待:WrKeyedEvent"并跟随堆栈

ntoskrnl.exe!KeWaitForMultipleObjects+0x0a
ntoskrnl.exe!ExfReleasePushLock+0x8ec
ntoskrnl.exe!_misaligned_access+0x331
ntdll.dll!ZwReleaseKeyedEvent+0xa
ntdll.dll!RtlFindMostSignificatBit+0xa0
ntdll.dll!RtlProcessFlsData+0xdc
ntdll.dll!LdrShutdownProcess+0xa9
ntdll.dll!RtlExitUserProcess+0x90
msvcrt.dll!wcstoui64+0x2fa
jvm.dll!JVM_Clone
jvm.dll!JVM_Clone
jvm.dll!JVM_Clone
jvm.dll!JVM_Clone
jvm.dll!JVM_Clone
jvm.dll!JVM_FindSignal
msvcrt.dll!srand
msvcrt.dll!ftime64_s
kernel32.dll!BaseThreadInitThunk
ntdll.dll!RtlUserThreadStart

有人知道,为什么java.exe没有结束?

Screenshot of the process explorer:

编辑有关回复"一个非反应线程仍在运行"

问题不在于Java应用程序中的剩余线程。 Java应用程序有几个正在运行的(Java-)线程,即使其中只有一个是非deamon的。

对于ShutdownHook也是如此。见这个例子:

/** Main class */
public class TestShutdown
{
    public static void main (final String[] args) throws FileNotFoundException
    {
        Runtime.getRuntime().addShutdownHook(new HookThread());
    }

}

/** The hook Thread */
final class HookThread extends Thread
{

    public HookThread()
    {
        super(HookThread.class.getName();
    }

    @Override
    public void run()
    {
        try
        {
            sleep(5000l);
        } catch (final InterruptedException ex) { throw new Error(); }

        final StringBuilder sb = new StringBuilder();
        Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
        sb.append("Number of threads: " + traces.size() + "\n");
        for (final Thread th: traces.keySet())
        {
            sb.append("-----------------\n");
            sb.append(th.toString()+"  "+ (th.isDaemon() ? " (deamon) " : " (not deamon) ") + "\n");
            final StackTraceElement[] trace = traces.get(th);
            for (int j=0; j < trace.length; j++)
                sb.append("  at " + trace[j] + "\n");
        }
        System.out.println(sb.toString());
    }

}

结果:

Number of threads: 6
-----------------
Thread[Reference Handler,10,system]   (deamon)
  at java.lang.Object.wait(Native Method)
  at java.lang.Object.wait(Unknown Source)
  at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)
-----------------
Thread[Finalizer,8,system]   (deamon)
  at java.lang.Object.wait(Native Method)
  at java.lang.ref.ReferenceQueue.remove(Unknown Source)
  at java.lang.ref.ReferenceQueue.remove(Unknown Source)
  at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)
-----------------
Thread[HookThread,5,main]   (not deamon)
  at java.lang.Thread.dumpThreads(Native Method)
  at java.lang.Thread.getAllStackTraces(Unknown Source)
  at HookThread.run(TestShutdown.java:59)
-----------------
Thread[Attach Listener,5,system]   (deamon)
-----------------
Thread[DestroyJavaVM,5,main]   (not deamon)
  at java.lang.Object.wait(Native Method)
  at java.lang.Thread.join(Unknown Source)
  at java.lang.Thread.join(Unknown Source)
  at java.lang.ApplicationShutdownHooks.runHooks(Unknown Source)
  at java.lang.ApplicationShutdownHooks$1.run(Unknown Source)
  at java.lang.Shutdown.runHooks(Unknown Source)
  at java.lang.Shutdown.sequence(Unknown Source)
  at java.lang.Shutdown.shutdown(Unknown Source)
-----------------
Thread[Signal Dispatcher,9,system]   (deamon)

(顺便说一下:在这种情况下,我们有两个不是deamons:钩子线程和DestroyJavaVM,它已经启动钩子并等待它结束。)

但是:我的悬挂java.exe只有一个操作系统 - 线程!并且很明显程序java.exe必须拥有更多的线程作为在其虚拟机中运行的应用程序......(在上面的程序中,6个Java线程在VM中运行但是java.exe进程本身就是17个OS线程。)

2 个答案:

答案 0 :(得分:1)

如果关闭挂钩或终结器未完成,则会发生这种情况。您是否有关闭钩子或者您是否启用了Runtime.runFinalizersOnExit?

无论如何,如果您是开发人员,您可以启动一个额外的线程来监视其他线程正在做什么。见Get a List of all Threads currently running in Java

答案 1 :(得分:0)

你的java应用程序没有结束,因为它中的某个线程永远循环或者资源上有挂起的锁 - 这证明了 bug ,你需要联系java应用程序开发人员并告诉他你的目前的问题。

对于初学者来说:对于在生产环境中使用的应用程序而言,它通常是一个好主意,可以使用某种形式的监视程序 - 有几个经过良好测试的库用于此类目的 - 例如Apache commons Watchdog。像这样的类只是暂停/等待直到发生超时 - 此时它们将调用你提供的函数,建议在该函数中调用System.exit(1),有效地强制关闭。这是有效的,因为监视器是一个daemon thread,一旦其他所有东西已经死亡,它将被杀死#34; - 因此,如果您的应用程序在预先设定的超时时间内结束,看门狗将永远不会触发。