主Java线程终止时如何管理工作线程生命周期?

我想要实现以下功能:当我的应用程序启动时,主线程将启动1+个应该在后台运行的工作线程,并定期在幕后做些事情。 这些不应该阻止主线:一旦主要启动工人,它会继续做自己的事情,直到:

  • 主线程完成(正常应用程序终止) - 在命令行工具的情况下,这是当main(String[])方法的末尾到达时; 在Swing GUI的情况下,当用户选择File >> Exit菜单等时
  • 操作系统会抛出kill命令(SIGKILL等)
  • 在主线程中出现意外的未捕获的异常,有效地杀死它(这只是上面#1的unsolite版本)
  • 一旦从主线程开始/提交,我希望所有工作线程( 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并发性,并且正在尽我所能正确使用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会捕获你的异常,并允许你做需要做的事情(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! */
            }
        }
    
    链接地址: http://www.djcxy.com/p/92045.html

    上一篇: How to manage worker thread lifecycles when main Java thread terminates?

    下一篇: Threading in Java