jar 执行后,是什么让 java 进程保持活动状态?
我有一个 java jar 文件,正在从 Windows 命令提示符执行该文件。代码正常完成(即执行预期的操作),但 java 进程继续运行。该应用程序是单线程的。我需要在代码完成后按 Ctrl-c 停止该进程才能恢复命令提示符。
我假设我可以在 main 方法的末尾放置一个 System.exit(0) ,这可能会解决这个问题,但我的印象是这是没有必要的。 java进程在执行结束时在什么条件下保持活动状态?这是我的主要方法的外壳:
public static void main(String[] args) {
try {
//application code here
Logger.log("Now finished");
} catch (SomeExceptoin e) {
Logger.error("Some error occured");
}
}
其中记录器是我自己的令人难以置信的基本静态类,它只是将消息转储到 System.out.println() 。控制台中显示“现已完成”,但该进程继续运行。有什么想法吗?
编辑:根据要求,这里是记录器代码的所有荣耀(我确实警告过你:)
public class Logger {
public static void logInfo(String logMessage)
{
System.out.println(timestamp() + logMessage);
}
private static String timestamp()
{
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd hh:mm:ss");
String timestamp = "[" + formatter.format(new Date()) + "] ";
return timestamp;
}
}
编辑编辑:我在上面的尝试中添加了一个finally块,其中包含来自instanceofTom答案中链接的线程转储代码。这是输出:
... [2010.11.18 11:22:57] 输出完成。至此所有处理完毕。
线程名称:参考处理程序 java.lang.Object.wait(本机方法) java.lang.Object.wait(Object.java:485) java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
线程名称:Finalizer java.lang.Object.wait(本机方法) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132) java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
线程名称:Signal Dispatcher
线程名称:Attach Listener
线程名称:Java2D Disposer java.lang.Object.wait(本机方法) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132) sun.java2d.Disposer.run(Disposer.java:125) java.lang.Thread.run(Thread.java:619)
线程名称:main java.lang.Thread.getStackTrace(Thread.java:1436) com.my.code.WorkloadManager.visit(WorkloadManager.java:124) com.my.code.WorkloadManager.visit(WorkloadManager.java:138) com.my.code.WorkloadManager.main(WorkloadManager.java:71) sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) java.lang.reflect.Method.invoke(Method.java:597) org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56)
线程名称:com.google.inject.internal.Finalizer java.lang.Object.wait(本机方法) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132) com.google.inject.internal.Finalizer.run(Finalizer.java:114)
线程名称:AWT-Windows sun.awt.windows.WToolkit.eventLoop(本机方法) sun.awt.windows.WToolkit.run(WToolkit.java:291) java.lang.Thread.run(Thread.java:619)
线程名称:EventQueueMonitor-ComponentEvtDispatch java.lang.Object.wait(本机方法) java.lang.Object.wait(Object.java:485) com.sun.java.accessibility.util.ComponentEvtDispatchThread.run(EventQueueMonitor.java:616) ******* >********* 线程名称:参考处理程序 java.lang.Object.wait(本机方法) java.lang.Object.wait(Object.java:485) java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
线程名称:Finalizer java.lang.Object.wait(本机方法) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132) java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
线程名称:Signal Dispatcher
线程名称:Attach Listener
线程名称:Java2D Disposer java.lang.Object.wait(本机方法) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132) sun.java2d.Disposer.run(Disposer.java:125) java.lang.Thread.run(Thread.java:619)
线程名称:main java.lang.Thread.getStackTrace(Thread.java:1436) com.my.code.WorkloadManager.visit(WorkloadManager.java:124) com.my.code.WorkloadManager.visit(WorkloadManager.java:138) com.my.code.WorkloadManager.main(WorkloadManager.java:71) sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法) sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) java.lang.reflect.Method.invoke(Method.java:597) org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56)
线程名称:com.google.inject.internal.Finalizer java.lang.Object.wait(本机方法) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132) com.google.inject.internal.Finalizer.run(Finalizer.java:114)
线程名称:AWT-Windows sun.awt.windows.WToolkit.eventLoop(本机方法) sun.awt.windows.WToolkit.run(WToolkit.java:291) java.lang.Thread.run(Thread.java:619)
线程名称:EventQueueMonitor-ComponentEvtDispatch java.lang.Object.wait(本机方法) java.lang.Object.wait(Object.java:485) com.sun.java.accessibility.util.ComponentEvtDispatchThread.run(EventQueueMonitor.java:616)
I have a java jar file which I am executing from the windows command prompt. The code finishes normally (i.e. does what it is supposed to) but the java process continues to run. The application is single threaded. I need to hit Ctrl-c to stop the process after the code completes to get the command prompt back.
I assume that I could put a System.exit(0)
at the end of my main method which would presumably fix this, but I was under the impression that it wasn't necessary. Under what conditions are java processes kept alive at the end of execution? Here's the shell of my main method:
public static void main(String[] args) {
try {
//application code here
Logger.log("Now finished");
} catch (SomeExceptoin e) {
Logger.error("Some error occured");
}
}
Where the logger is my own incredibly basic static class which just dumps messages to System.out.println()
. "Now finished" appears in the console, but the process continues to run. Any ideas?
EDIT: As requested, here's the logger code in all its glory (I did warn you :)
public class Logger {
public static void logInfo(String logMessage)
{
System.out.println(timestamp() + logMessage);
}
private static String timestamp()
{
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd hh:mm:ss");
String timestamp = "[" + formatter.format(new Date()) + "] ";
return timestamp;
}
}
EDIT EDIT: I put a finally block onto my try above with the thread dump code from the link in instanceofTom's answer. Here's the output:
...
[2010.11.18 11:22:57] Output complete. All processing now finished.
Thread name: Reference Handler
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:485)
java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
Thread name: Finalizer
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
Thread name: Signal Dispatcher
Thread name: Attach Listener
Thread name: Java2D Disposer
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
sun.java2d.Disposer.run(Disposer.java:125)
java.lang.Thread.run(Thread.java:619)
Thread name: main
java.lang.Thread.getStackTrace(Thread.java:1436)
com.my.code.WorkloadManager.visit(WorkloadManager.java:124)
com.my.code.WorkloadManager.visit(WorkloadManager.java:138)
com.my.code.WorkloadManager.main(WorkloadManager.java:71)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56)
Thread name: com.google.inject.internal.Finalizer
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
com.google.inject.internal.Finalizer.run(Finalizer.java:114)
Thread name: AWT-Windows
sun.awt.windows.WToolkit.eventLoop(Native Method)
sun.awt.windows.WToolkit.run(WToolkit.java:291)
java.lang.Thread.run(Thread.java:619)
Thread name: EventQueueMonitor-ComponentEvtDispatch
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:485)
com.sun.java.accessibility.util.ComponentEvtDispatchThread.run(EventQueueMonitor.java:616) ****************
Thread name: Reference Handler
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:485)
java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
Thread name: Finalizer
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
Thread name: Signal Dispatcher
Thread name: Attach Listener
Thread name: Java2D Disposer
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
sun.java2d.Disposer.run(Disposer.java:125)
java.lang.Thread.run(Thread.java:619)
Thread name: main
java.lang.Thread.getStackTrace(Thread.java:1436)
com.my.code.WorkloadManager.visit(WorkloadManager.java:124)
com.my.code.WorkloadManager.visit(WorkloadManager.java:138)
com.my.code.WorkloadManager.main(WorkloadManager.java:71)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:56)
Thread name: com.google.inject.internal.Finalizer
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
com.google.inject.internal.Finalizer.run(Finalizer.java:114)
Thread name: AWT-Windows
sun.awt.windows.WToolkit.eventLoop(Native Method)
sun.awt.windows.WToolkit.run(WToolkit.java:291)
java.lang.Thread.run(Thread.java:619)
Thread name: EventQueueMonitor-ComponentEvtDispatch
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:485)
com.sun.java.accessibility.util.ComponentEvtDispatchThread.run(EventQueueMonitor.java:616)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
根据您的线程转储,看起来正在加载 Google 库之一(可能是 Guice 或 Guava)。
如果是这样,则此错误可能会导致问题:
这与终结器线程没有被正确释放有关。发布了各种解决方法。
Based on your thread dump, it looks like one of the Google libraries (perhaps Guice or Guava) is being loaded.
If so, then this bug could be causing the issue:
It is related to the finalizer thread not being let go correctly. There are various workarounds posted.
具有 UI 启动事件处理线程的 Java 应用程序不是“守护程序”线程。也就是说,只要这些线程正在运行,程序就不会终止——即使当前没有显示窗口。
您的菜单上有“退出”命令吗?它的
Action
应调用System.exit(0)
。Java applications with a UI start event handling threads that are not "daemon" threads. That is, the program will not terminate as long as these threads are running—even if no windows are currently displayed.
Do you have an "Exit" command on your menu? Its
Action
should invokeSystem.exit(0)
.如果代码中的一切看起来正常,则可能有一个孤立线程仍在运行。
此处的代码描述了如何列出当前正在运行的所有线程JVM
或者,您可以使用探查器或带有内置探查器的 IDE 来查看正在运行的线程。
如果您能让我们知道代码完成后哪些线程仍在运行,这将有助于回答这个问题; 即使您的代码可能是单线程的,JVM 中仍可能运行其他线程,例如垃圾收集线程(尽管 GC 线程不会阻止 JVM 退出)
If everything in your code seems normal it is likely that there is an orphaned thread still running.
The code here describes how to list all of the threads currently running in the JVM
Alternatively you could use a profiler or IDE with built-in profiler to view the running threads.
It would help in answering this question if you could let us know what threads are still running when your code is finished; Even though your code may be single threaded there will likely still be other threads running in the JVM such as the garbage collection thread ( Although GC threads wont stop the JVM from exiting )
只要 Java 进程有一个或多个非守护线程在运行,它就会保持活动状态。
考虑使用位于 Java JDK 的 bin 目录中的 JVisualVM 并将其附加到您的 Java 程序。在那里,您将能够对活动线程及其状态进行分析以及执行线程转储。
A Java process will remain alive so long as it has one or more non-daemon threads running.
Consider using JVisualVM located in the Java JDK's bin directory and attach it to your Java program. There you will be able to perform an analysis of active Threads and their state as well as perform a thread dump.