调度程序启动一个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没有结束?
编辑有关回复"一个非反应线程仍在运行"
问题不在于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线程。)
答案 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; - 因此,如果您的应用程序在预先设定的超时时间内结束,看门狗将永远不会触发。