我已经使用apache jsvc在Linux上部署了Java服务应用程序。这是一个多线程应用程序,但是当启动守护程序停止时,它将在所有线程完成之前杀死jvm。
它是这样的:
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;
}
但是我仍然不知道为什么会这样...有什么想法吗?