JSVC守护程序停止不等待线程完成

时间:2019-08-26 08:07:14

标签: java multithreading jsvc

我已经使用apache jsvc在Linux上部署了Java服务应用程序。这是一个多线程应用程序,但是当启动守护程序停止时,它将在所有线程完成之前杀死jvm。

它是这样的:

  1. 实现守护程序接口的WorkerLauncher,启动服务
  2. WorkerPool类初始化由Worker类表示的父线程和工作线程(子线程)。
  3. 当调用WorkerLauncher stop时,WorkerPool线程被中断,并且此InterruptedException被捕获,子线程也被中断。
  4. 子线程被中断时,它将在停止之前执行计算。 这是出问题的地方:我猜想在线程被杀死之前计算还没有完成(在这里不太确定)。

WorkerLauncher

public class WorkerLauncher implements Daemon {
    private static final Logger log = LoggerFactory.getLogger("com.worker");

    private WorkerPool pool;

    @Override
    public void init(DaemonContext context) {
    }

    @Override
    public void start()  {
        log.info("Starting worker pool...");
        if (pool == null) pool = new WorkerPool();
        pool.start();
        log.info("Worker pool started");
    }

    @Override
    public void stop(){
        pool.stop();
    }

    @Override
    public void destroy() {
        pool = null;
    }
}

WorkerPool

public class WorkerPool implements Runnable {
    private static final Logger log = LoggerFactory.getLogger("com.worker");

    private Thread thread = null;

    private List<Thread> workers = new ArrayList<Thread>();

    public WorkerPool() {
        for (int i = 0; i < 1; i++) workers.add(new Thread(new Worker("Worker "+i), "Worker "+i));
        this.thread = new Thread(this, "Worker Main");
    }

    @Override
    public void run() {
        for (Thread thread : workers) {
            thread.start();
        }

        while (isRunning()) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                log.info("Worker pool stopping");
                for (Thread worker : workers) {
                    worker.interrupt();
                }
                break;
            }
        }
    }

    public boolean isRunning() {
        return !thread.isInterrupted();
    }

    public void stop() {
        thread.interrupt();
    }

    public void start() {
        thread.start();
    }
}

工人

public class Worker implements Runnable{
    private static final Logger log = LoggerFactory.getLogger("com.worker");

    private String name;

    public Worker(String name) {
        this.name = name;
    }

    private void stop() {
        longCalculations();
        log.info("Worker {] stopped", name);
    }

    @Override
    public void run() {
        try {
            try {
                while (true) {
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                log.info("InterruptedException");
            }
        } finally {
            stop();
        }
    }

    private void longCalculations() {
        for (int i = 0; i < 99999; i++) {
            for (int j = 0; j < 9999; j++) {
                Math.round(i + j * 0.999);
            }
        }
    }

}

这只是真实应用程序中的一个示例,但是与此同时,我重现了相同的问题。 commons-daemon 1.1和1.2版本经过测试。如果长计算被删除或持续时间较短(性能更好),则一切正常。我在这里想念什么?有什么想法吗?

这是日志输出的样子:

07:55:10.790 (      main) INFO  Starting worker pool...
07:55:10.791 (      main) INFO  Worker pool started
07:55:34.056 (Worker Main) INFO  Worker pool stopping
07:55:34.057 (  Worker 0) INFO  InterruptedException

请注意Worker {] stopped的丢失方式。在实际的应用程序中,由worker启动的第三方进程仍在运行,即使在进程中未显示jsvc,也可以在ps -A中看到。

编辑

修改后的stop()方法:

private void stop() {
    log.info("Worker {] being stopped", name);
    longCalculations();
    log.info("Worker {] stopped", name);
}

日志输出:

06:18:55.762 (      main) INFO  Starting worker pool...
06:18:55.764 (      main) INFO  Worker pool started
06:19:08.614 (Worker Main) INFO  Worker pool stopping
06:19:08.615 (  Worker 0) INFO  InterruptedException
06:19:08.616 (  Worker 0) INFO  Worker {] being stopped

我使用jsvc 启动/停止该服务:

开始

./jsvc -cwd . -cp commons-daemon-1.1.0.jar:multithread-test.jar -outfile /tmp/worker.out -errfile /tmp/worker.err -pidfile /var/run/worker.pid com.worker.WorkerLauncher

停止

./jsvc -cwd . -cp commons-daemon-1.1.0.jar:multithread-test.jar -outfile /tmp/worker.out -errfile /tmp/worker.err -pidfile /var/run/worker.pid -stop com.worker.WorkerLauncher

重要!

忘记了,该应用程序在使用apache procun的Windows上可以按预期工作。这仅在使用jsvc在Linux上启动时发生。

另一项编辑

如果我在isAlive中的pool.stop()之后等待线程结束(检查是否有任何工作线程WorkerLauncher.stop()),一切正常。

@Override
public void stop(){
    pool.stop();
    while(pool.isAnyGuardianRunning()) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            break;
        }
    }
}

在WorkerPool中:

public boolean isAnyGuardianRunning() {
    for (Thread thread : workers) {
        if (thread.isAlive()) return true;
    }
    return false;
}

但是我仍然不知道为什么会这样...有什么想法吗?

0 个答案:

没有答案