我正在尝试添加对信号的支持(尤其是Ctrl + C)。
我的工具是用Java编写的,当我发现Ctrl+C
时,我想执行清理。
我的主文件是应用程序,代码如下:
if (ArgDefinitions.getInstance().hasOption(ArgNames.EXECUTE)) {
performShutdownHooks();
preformRun();
}
应用程序解析用户的选项并运行适当的方法。因此,当用户使用execute
选项并单击Ctrl+C
时,我希望程序停止并清理该区域。
我添加了performShutdownHooks
方法以处理信号,它看起来如下:
private void performShutdownHooks() {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
performCleanup();
}
});
}
它可以执行我想要的操作-如果我运行该工具并在运行时将其杀死,则会进行清理(它会在后台运行一个特殊命令)。 当我不停止时,就会出现问题。我收到以下异常:
Exception in thread "Thread-2" java.lang.IllegalStateException: Job manager has been shut down.
at org.eclipse.core.internal.jobs.JobManager.schedule(JobManager.java:1104)
at org.eclipse.core.internal.jobs.InternalJob.schedule(InternalJob.java:427)
at org.eclipse.core.runtime.jobs.Job.schedule(Job.java:436)
at glichautil.CommandExecutor.runCommandInBackground(CommandExecutor.java:134)
at glicha.core.Application.performCleanup(Application.java:869)
at glicha.core.Application.access$0(Application.java:838)
at glicha.core.Application$1.run(Application.java:985)
我认为performShutdownHooks
最后运行了,即使我没有试图杀死它。
也许还有其他东西可以杀死它,但它不应该杀死它,因为如果我将方法调用performShutdownHooks()
注释掉,它可以正常工作(不会引发任何异常)。
这使我相信,由于某种原因,即使我没有按performShutdownHooks
,方法Ctrl+C
仍在运行。
为了解决它,我需要添加到performShutdownHooks
方法中吗?也许我错过了一些有关addShutdownHook
的信息?
如果这是对问题的正确解释,那么我认为,如果我能以某种方式使它在最后运行,那么它将解决问题。
在代码中使用的其他一些线程也有可能被杀死,并出于某种原因执行该方法。
编辑:我认为我已经理解了它为什么这样工作。在输入我的ShutdownHooks
方法之前,它会打印:
Job found still running after platform shutdown.
Jobs should be canceled by the plugin that scheduled them during shutdown: glicha.testmanager.HandleParallelJobs.
我想这就是调用ShutdownHooks
的原因。问题是,我不知道如何解决。我从文档中读到:
Java虚拟机因以下两种事件而关闭:
当最后一个非守护程序线程退出时,或者在调用exit(相当于System.exit)方法时,程序会正常退出,或者
响应于用户中断(例如键入 Ctrl + C )或系统范围的事件(例如用户注销),虚拟机将终止或系统关闭。
所以我想,当插件关闭时,它会调用ShutdownHooks
(如果我输入错了,请纠正我)。问题是我不了解如何在这两种可能性之间进行区分。我只想捕获信号并执行清理,但是如果其中一台VM关闭,我不想这样做。关于如何处理此问题的任何想法?
答案 0 :(得分:0)
关闭挂钩的常见问题之一是没有确定的关闭顺序。在您的情况下,我假设<com.github.mikephil.charting.charts.PieChart
android:id="@+id/fragment_chart"
android:layout_width="match_parent"
android:layout_height="400dp" />
框架可能已经具有一个单独的shutdown钩子,该钩子已经执行了清除(停止任务)。
与关闭挂钩相关的javadoc在某种程度上解释了您不能依赖Schedule
的存在,因为它们可能已经关闭了。
现在,当您尝试在关机挂钩中执行此操作时,可能会收到上述错误,具体取决于关机挂钩的执行顺序。
所有这些都不是您真正想要的,但是我想您可能根本没有问题。我宁愿讨论以下内容
您可能需要添加在清理问题时运行的代码。根据我得到的信息,您可能想要关闭已经关闭的设备。
如果您仍然想进行Singal拦截,实际上有一种方法,但我不建议这样做。根据{{3}}这个链接,您可以使用sun.misc。*软件包的Signal类。
sun.misc软件包仅包含非官方的API,可以随时将其删除而无需另行通知。似乎没有官方的API支持您的用例(至少据我所知)。
答案 1 :(得分:0)
您可以覆盖SecurityManager
checkExit(int status)
方法-如果在任何地方显式调用System.exit(status)
都可以使用-但是,当应用程序“正常”退出时,它不会设置状态(否活动线程),或者错误会杀死VM。
System.setSecurityManager(new ExitMonitorSecurityManager());
Runtime.getRuntime().addShutdownHook(new Thread(new MyShutdownHook()));
private static class ExitMonitorSecurityManager extends SecurityManager {
@Override
public void checkPermission(Permission perm) {
//Something;
}
@Override
public void checkPermission(Permission perm, Object context) {
//Something
}
@Override
public void checkExit(int status) {
System.out.println("Setting exit value via security manager...");
MyShutdownHook.EXIT_STATUS = status;
}
}
private static class MyShutdownHook implements Runnable {
public static Integer EXIT_STATUS;
public void run() {
System.out.println("In MyShutdownHook - exit status is " + EXIT_STATUS);
}
}