[英]How to manage worker thread lifecycles when main Java thread terminates?
我想要实现以下目标:当我的应用程序启动时,主线程将启动应在后台运行的1+个工作线程,并定期在后台进行操作。 这些不应阻塞主线程:一旦main启动了工作程序,它将继续做自己的事情,直到:
main(String[])
方法的末尾时; 对于Swing GUI,可能是用户选择File >> Exit
菜单等时。 从主线程启动/提交后,我希望所有工作线程( Runnable
)基本上都有自己的生命周期,并且独立于主线程而存在。 但是,如果主线程在任何时间死掉,我希望能够阻塞(如果可能的话)主线程,直到所有工作线程都关闭, 然后 “允许”主线程死掉。
到目前为止,我一直尽力而为,尽管我知道我在这里和那里都缺少片段:
public class MainDriver {
private BaneWorker baneWorker;
private ExecutorService executor = Executors.newCachedThreadPool();
public static void main(String[] args) {
MainDriver driver = new MainDriver();
driver.run();
// We've now reached the end of the main method. All workers should block while they shutdown
// gracefully (if at all possible).
if(executor.awaitTermination(30, TimeUnit.SECONDS))
System.out.println("Shutting down...");
else {
System.out.println("Forcing shut down...");
executor.shutdownNow();
}
}
private void run() {
// Start all worker threads.
baneWorker = new BaneWorker(Thread.currentThread());
// More workers will be used once I get this simple example up and running...
executor.submit(baneWorker);
// Eventually submit the other workers here as well...
// Now start processing. If command-line utility, start doing whatever the utility
// needs to do. If Swing GUI, fire up a parent JFrame and draw the application to the
// screen for the user, etc.
doStuff();
}
private void doStuff() {
// ??? whatever
}
}
public class BaneWorker implements Runnable {
private Timer timer;
private TimerTask baneTask;
private Thread mainThread;
public BaneWorker(Thread mainThread) {
super();
this.mainThread = mainThread;
}
@Override
public void run() {
try {
timer = new Timer();
baneTask = new TimerTask() {
@Override
public void run() {
System.out.println("When the main thread is ashes...");
}
};
// Schedule the baneTask to kick off every minute starting now.
timer.scheduleAtFixedRate(baneTask, new Date(), 60 * 1000);
} catch(InterruptedException interrupt) {
// Should be thrown if main thread dies, terminates, throws an exception, etc.
// Should block main thread from finally terminating until we're done shutting down.
shutdown();
}
}
private void shutdown() {
baneTask.cancel();
System.out.println("...then you have my permission to die.");
try {
mainThread.join();
} catch(InterruptedException interrupt) {
interrupt.printStackTrace;
}
}
}
我在这里吗? 我需要进行哪些更改才能按照需要的方式进行此工作? 我是Java并发的新手,正在尽最大努力正确使用Concurrency API,但有些困难。 有任何想法吗? 提前致谢!
主线程必须向工作线程发出终止信号(通常是通过使用标志来实现),然后它应在每个线程上调用join
来等待其终止。 在这里看看: Java:如何使用Thread.join
您可以使用Runtime.addShutdownHook来注册未启动的线程,该线程在JVM终止,系统关闭等情况下执行。此代码可以自行清理,或者通知正在运行的守护程序线程完成其工作。 任何这样的清理代码必须相对较快,因为在许多系统上,程序在被强制终止之前只有有限的时间进行清理。
也许您还可以考虑使后台线程守护程序线程成为线程 。 这样,当main
完成时,它们将不会阻塞JVM,并且在清理阶段仍将继续运行。
请注意,您无法截获SIGKILL-此信号被设计为不可避免且立即发生。 但它应与SIGTERM,SIGHUP和类似信号一起使用。
更新:您可以轻松创建运行守护程序线程的ExecutorService
。 您只需要创建一个合适的ThreadFactory
:
public static class DaemonFactory
implements ThreadFactory
{
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
}
比您创建一个ExecutorService
类的
public static void main(String argv[])
throws Exception
{
ExecutorService es
= Executors.newCachedThreadPool(new DaemonFactory());
// ^^^^^^^^^^^^^^^^^^^
es.submit(new Callable<Object>() {
public Object call() throws Exception {
Thread.sleep(100);
System.err.println("Daemon: " +
Thread.currentThread().isDaemon());
return null;
}
});
// Without this, JVM will terminate before the daemon thread prints the
// message, because JVM doesn't wait for daemon threads when
// terminating:
es.awaitTermination(3, TimeUnit.SECONDS);
}
关于Thread.join()
,您不应尝试在ExecutorService
管理的线程上使用它。 执行者负责管理它们。 您没有可靠的方法枚举其线程,执行程序可以根据其配置创建和销毁线程。唯一可靠的方法是调用shutdown();
然后awaitTermination(...);
。
如果SIGKILL是Unix的“ kill -9”,您将无能为力。
对于正常的退出,在主目录中使用try / catch / finally。 catch
将捕获您的异常,并允许您执行需要做的事情(恢复吗?中止?) finally
将使您有个钩子,可以优雅地旋转线程。
快速查看您的代码,我看不到您在哪里跟踪线程实例。 如果您要告诉他们降低速度,则将需要这些。
伪代码:
static Main(...) {
ArrayList threads = new ArrayList();
try {
for (each thread you want to spin up) {
threads.add(a new Thread())
}
}
catch { assuming all are fatal. }
finally {
for(each thread t in threads) {
t.shutdown();
t.join(); /* Be prepared to catch (and probably ignore) an exception on this, if shutdown() happens too fast! */
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.