我是Java / threads的新手,我继承了类似下面的代码。它是一个命令行程序,main()只启动5-6种不同类型的线程,并以^ C退出。我想添加一个关闭钩子来正确关闭所有线程并按以下方式调整它。
我在所有线程中添加了Shutdown钩子和stopThread()方法(比如MyWorker类中的那个)
问题是当我按下^ C时,我没有看到Thread的run方法中的结束消息。这是在后台完成还是我的方法有问题。另外,我应该遵循更好的模式吗?
由于
public class Main {
public static MyWorker worker1 = new MyWorker();
// .. various other threads here
public static void startThreads() {
worker1.start();
// .. start other threads
}
public static void stopThreads() {
worker1.stopThread();
// .. stop other threads
}
public static void main(String[] args)
throws Exception {
startThreads();
// TODO this needs more work (later)
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
stopThreads();
} catch (Exception exp) {
}
}
});
} }
public class MyWorker extends Thread {
private volatile boolean stop = false;
public void stopThread() {
stop = true;
}
public void run() {
while (!stop) {
// Do stuff here
}
// Print exit message with logger
}
}
答案 0 :(得分:7)
当您调用System.exit()或通过信号终止时,它会停止所有现有线程并启动所有关闭挂钩。也就是说,当你开始挂钩时,你所有的线程都可能已经死了。
您应该确保干净地关闭资源,而不是试图干净地停止线程。
答案 1 :(得分:6)
在某些情况下可能无法执行关机挂钩!
首先要记住的是,无法保证关闭挂钩始终会运行。如果JVM由于某些内部错误而崩溃,那么它可能会在没有机会执行单个指令的情况下崩溃。此外,如果O / S给出SIGKILL(http://en.wikipedia.org/wiki/SIGKILL)信号(Unix / Linux中的kill -9)或TerminateProcess(Windows),则应用程序需要立即终止,而不必等待任何清理活动。除了上述内容之外,还可以通过调用Runime.halt()方法来终止JVM而不允许关闭挂钩运行。
当应用程序正常终止时(当所有线程完成或调用System.exit(0)时)将调用关闭挂钩。此外,当JVM由于外部原因(例如用户请求终止(Ctrl + C))而关闭时,由O / S(正常kill命令,不带-9)或操作系统关闭时发出SIGTERM
答案 2 :(得分:5)
我猜您可以将代码转移到ExectuterService
private final ExecutorService pool;
pool = Executors.newFixedThreadPool(poolSize);
pool.execute(Instance of Runnable);
pool.shutdown();
启动有序关闭,其中先前提交的任务已执行,但不会接受任何新任务。如果已经关闭,调用没有其他影响。
答案 3 :(得分:1)
尝试将您的线程作为守护程序线程。
添加构造函数
public MyWorker(boolean isDaemon) {
this.setDaemon(true);
}
或在调用start之前设置为守护进程。
worker1.setDaemon(true);
worker1.start();
按Ctrl C并退出时,线程将停止。
答案 4 :(得分:0)
这里发生的是您调用stopThread()
方法,但是在终止之前不要等待线程实际完成。
如果在停止JVM之前在所有线程上调用join()
,您可能会看到“停止日志”。
public static void stopThreads() {
worker1.stopThread();
// .. stop other threads
for(Thread t: workers) {
t.join();
}
}