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

6 java concurrency multithreading executorservice

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

  1. 主线程完成(正常的应用程序终止) - 在命令行实用程序的情况下,这是在main(String[])到达方法的结尾时; 在Swing GUI的情况下,可以是当用户选择File >> Exit菜单等时.
  2. 操作系统抛出kill命令(SIGKILL等)
  3. 主线程中发生了一个意外的,未捕获的异常,有效地将其杀死(这只是上面#1的一个非人类版本)

一旦从主线程启动/提交,我希望所有工作线程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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我是在赛道上还是离开这里?我需要改变什么来使我的工作方式符合我的需要?我是Java并发的新手,我正在尽我所能正确使用并发API,但有点磕磕绊绊.有任何想法吗?提前致谢!

Ton*_*nis 0

如果 SIGKILL 是 unix“kill -9”,那么您无能为力。

为了优雅退出,请在 main.c 中使用 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! */
        }
    }
Run Code Online (Sandbox Code Playgroud)