linux正确停止java应用进程

在Linux系统下,写的应用程序,每次重新启动时,经常会有启动不成功的情况,困惑了好久。

后来在网上搜索到一篇文章,试了一下,问题解决了。原来的脚本是用kill -9 命令来杀死java应用进程,-9比较暴力,会造成资源释放不掉的问题。根据文章提示,修改为 -15,问题解决

 

在linux/unix下,你会怎么中止一个java应用或进程?

  多数人可能会回答 kill -9 pid,这是一种在多数情况下正确的做法。不过本文打算阐述使用kill -9带来的一些问题,并给出另一种标准的kill方式。

  标准中断信号

  在Linux信号机制中,存在多种进程中断信号(Linux信号列表 )。其中比较典型的有 SIGNKILL(9) 和 SIGNTERM(15).

  SIGNKILL(9) 和 SIGNTERM(15) 的区别在于:

  SIGNKILL(9) 的效果是立即杀死进程. 该信号不能被阻塞, 处理和忽略。

  SIGNTERM(15) 的效果是正常退出进程,退出前可以被阻塞或回调处理。并且它是Linux缺省的程序中断信号。

  由此可见,SIGNTERM(15) 才是理论上标准的kill进程信号。

  那使用 SIGNKILL(9) 又有什么错呢?

  SIGNKILL(9) 带来的问题

  先看一段程序

  Java代码

  /**

  * Shutdown Hook Presentation

  *

  */

  public class ShutdownHookTest {

  private static final void shutdownCallback() {

  System.out.println("Shutdown callback is invoked.");

  }

  public static void main(String[] args) throws InterruptedException {

  Runtime.getRuntime().addShutdownHook(new Thread() {

  @Override

  public void run() {

  shutdownCallback();

  }

  });

 Thread.sleep(10000);

  }

  }

  /**

  * Shutdown Hook Presentation

  *

  */

  public class ShutdownHookTest {

  private static final void shutdownCallback() {

  System.out.println("Shutdown callback is invoked.");

  }

  public static void main(String[] args) throws InterruptedException {

  Runtime.getRuntime().addShutdownHook(new Thread() {

  @Override

  public void run() {

  shutdownCallback();

  }

  });

  Thread.sleep(10000);

  }

  }

  在上面这段程序中,我使用Runtime为当前java进程添加了一个ShutdownHook,它的作用是在java正常退出时,执行shutdownCallback()这个回调方法。

  此时,如果你试验过在java进程未自动退出前,执行 kill -9 pid,即发送 SIGNKILL 信号,会发现这个回调接口是不会被执行的。这是SIGNKILL信号起的作用。

  对于我这个简单的测试用例来说,不被执行也无大碍。但是,如果你的真实系统中有需要在java进程退出后,释放某些资源。

  而这个释放动作,因为SIGNKILL被忽略了,那就可能造成一些问题。

  所以,推荐大家使用标准的kill进程方式,即 kill -15 pid。

 

文章来源:  http://edu.shangdu.com/pc/erji/JAVA/slbc/201111/245631.html

<think>嗯,用户想在Linux环境下用Java实现守护进程,这需要结合Java的特性和Linux的守护进程机制。首先,我得回忆一下守护进程的基本概念。根据引用[5],守护进程是在后台运行,没有控制终端的进程,通常用于服务任务。比如像httpd这样的服务器程序。 那Java程序怎么变成守护进程呢?通常Java应用是在前台运行的,如果直接运行,终端关闭后进程可能就结束了。所以需要找到方法让它在后台运行,并且符合守护进程的特点。用户提到的引用[2]和[4]提到可以使用Apache Commons Daemon的jsvc工具,或者Java Service Wrapper。可能这两个是常用的方法,需要详细说明。 首先,Apache Commons Daemon的jsvc。用户需要下载并安装这个工具,然后编写一个符合特定接口的Java类,实现init、start、stop、destroy方法。然后通过jsvc命令来启动,这样就能作为守护进程运行了。例如,用户提供的DaemonExample类,应该就是这种方式的示例代码。 然后,Java自带的setDaemon方法,可能指的是将线程设置为守护线程,但这里用户是要整个Java进程成为守护进程。所以可能这个方法的说明需要更准确。或者,用户可能混淆了线程和进程的概念。这里需要澄清,Java中的守护线程和系统级的守护进程是不同的。 另外,用户提供的示例代码可能应该包括如何用jsvc来运行,比如具体的命令行参数,安装步骤等。同时,守护进程需要处理信号,如SIGTERM,以便优雅退出。引用[1]提到优雅终止的重要性,所以在Java中可能需要注册shutdown hook,或者通过jsvc的stop方法处理资源释放。 还要考虑日志管理,守护进程通常会把输出重定向到日志文件,而不是控制台。引用[3]中的C示例关闭了标准输入输出,Java程序可能需要类似处理,比如使用日志框架如Log4j或SLF4J,并将输出重定向到文件。 另外,用户可能需要知道如何将守护进程设置为开机启动,这通常涉及到在/etc/init.d或systemd中创建服务单元文件。例如,使用jsvc的话,可能需要编写一个systemd的service文件,定义启动和停止的命令。 现在,用户要求示例代码,所以需要给出具体的Java类,以及如何使用jsvc运行的命令。例如,DaemonExample类,然后编译成jar,再通过jsvc命令启动。同时,解释每个参数的意义,比如-user指定运行用户,-pidfile保存进程ID,-outfile和-errfile重定向输出。 另外,可能还要提到其他方法,比如使用nohup和&在后台运行,但这种方法可能不够可靠,无法处理系统启动时自动运行,或者无法正确响应停止信号,所以推荐使用专业的工具如jsvc。 最后,确保回答结构清晰,分步骤说明不同的实现方式,强调优雅终止和日志管理的重要性,并给出相关的问题供用户进一步参考。</think>### 如何在 Linux 中创建 Java 守护进程Linux 环境下将 Java 程序作为守护进程运行,需结合系统级守护进程特性与 Java 程序管理。以下是两种常见实现方式及其示例代码: --- #### 方法 1:使用 Apache Commons Daemon (jsvc) **核心步骤**: 1. **安装依赖** 安装 `jsvc` 工具(需 JDK 和 Apache Commons Daemon 库): ```bash sudo apt-get install jsvc ``` 2. **编写 Java 守护类** 实现 `init`、`start`、`stop`、`destroy` 方法: ```java public class DaemonExample implements org.apache.commons.daemon.Daemon { private Thread worker; public void init(DaemonContext context) throws Exception { // 初始化逻辑(如加载配置) } public void start() { worker = new Thread(() -> { while (!Thread.interrupted()) { // 执行守护进程任务(如定时任务) try { Thread.sleep(5000); } catch (InterruptedException e) { break; } } }); worker.start(); } public void stop() { worker.interrupt(); // 优雅终止线程 } public void destroy() { // 清理资源(如关闭数据库连接) } } ``` 3. **编译与部署** 编译为 JAR 文件,使用 `jsvc` 启动守护进程: ```bash jsvc -user nobody -pidfile /var/run/daemon.pid \ -outfile /var/log/daemon.out -errfile /var/log/daemon.err \ -cp /path/to/your.jar DaemonExample ``` - `-user`:指定运行用户 - `-pidfile`:记录进程 ID - `-outfile/-errfile`:重定向日志[^2] --- #### 方法 2:通过 Systemd 管理(推荐) **核心步骤**: 1. **编写 Java 程序** 添加 `Shutdown Hook` 实现优雅终止: ```java public class SystemdDaemon { public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("Shutting down gracefully..."); // 清理资源 })); while (true) { try { Thread.sleep(5000); } catch (InterruptedException e) { break; } } } } ``` 2. **创建 Systemd 服务文件** 在 `/etc/systemd/system/` 下创建 `javadaemon.service`: ```ini [Unit] Description=Java Daemon Service After=network.target [Service] User=nobody ExecStart=/usr/bin/java -jar /path/to/your.jar Restart=always KillSignal=SIGTERM [Install] WantedBy=multi-user.target ``` 3. **启动与管理** ```bash sudo systemctl daemon-reload sudo systemctl start javadaemon sudo systemctl enable javadaemon # 开机自启 ``` - `KillSignal=SIGTERM` 确保触发 Shutdown Hook[^1] --- #### 关键注意事项 1. **日志管理** 避免使用 `System.out`,改用 `SLF4J` 或 `Log4j2` 并配置日志文件。 2. **信号处理** 注册 `SignalHandler` 处理 `SIGTERM` 以实现优雅终止[^5]。 3. **权限隔离** 以非 root 用户(如 `nobody`)运行降低安全风险。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值