我想实现以下目标:当我的应用程序启动时,主线程将启动应该在后台运行的1+工作线程,并定期在幕后执行操作。这些不应该阻止主线程:一旦主要启动工作人员,它继续做自己的事情,直到:
main(String[])
方法的结尾时;对于Swing GUI,可以是用户选择File >> Exit
菜单等从主线程启动/提交后,我希望所有工作线程(Runnable
s)基本上都有自己的生命周期,并且独立于主线程存在。但是,如果主线程在任何时候死亡,我希望能够阻止(如果可能的话)主线程,直到所有工作人员完成关闭,然后然后“允许”主线程线程死了。
到目前为止,我是最好的尝试,虽然我知道我在这里和那里都缺少一些东西:
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并发的新手,我正在尽我所能正确使用并发API,但有点磕磕绊绊。有任何想法吗?提前谢谢!
答案 0 :(得分:1)
主线程必须通知工作线程终止(通常这只是通过使用标志来实现)然后它应该在每个线程上调用join
以等待它们的终止。看看这里:Java: How to use Thread.join
答案 1 :(得分:1)
您可以使用Runtime.addShutdownHook注册在JVM终止,系统正在关闭等时执行的未启动线程。此代码本身可以进行一些清理,或者可能通知正在运行的守护程序线程完成他们的工作。任何这样的清理代码必须相对较快,因为在许多系统上,程序在被强制终止之前只有有限的时间进行清理。
也许您也可以考虑制作后台帖子daemon threads。然后,当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(...);
。
答案 2 :(得分:0)
如果SIGKILL是unix“kill -9”,你就无能为力了。
对于优雅的退出,请在主体中使用try / catch / finally。 catch
将捕获您的异常并允许您执行需要执行的操作(recover?abort?)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! */
}
}