杰瑞科技汇

Linux下Java如何后台运行?

核心概念

我们需要理解“后台运行”的几个关键点:

Linux下Java如何后台运行?-图1
(图片来源网络,侵删)
  1. 脱离终端:程序启动后,即使你关闭了 SSH 终端窗口,程序也应该继续运行。
  2. 输入输出重定向:程序在后台运行时,它的标准输入、标准输出和标准错误需要被妥善处理,否则它们可能会阻塞程序或产生大量无用的日志文件。
  3. 进程管理:能够方便地启动、停止、查看状态和重启程序。
  4. 守护进程化:理想的 Java 后台服务应该像一个系统守护进程一样,在系统启动时自动启动,在系统关闭时自动关闭。

使用 nohup& (最简单,适合临时任务)

这是最基础的后台运行方式,非常适合用来临时启动一个程序,或者用于测试。

命令

nohup java -jar your-app.jar > app.log 2>&1 &

命令分解

  • java -jar your-app.jar:这是你的 Java 程序启动命令。
  • &:这个符号的作用是将命令在后台执行,你执行完命令后,终端会立即返回,不会阻塞。
  • nohupno Hang Up 的缩写,它的作用是让进程忽略 SIGHUP 信号,默认情况下,当你关闭终端时,终端会向所有它启动的子进程发送 SIGHUP 信号,导致进程退出。nohup 阻止了这一点。
  • > app.log:这是输出重定向,它将程序的标准输出 重定向到 app.log 这个文件中。
  • 2>&1:这是错误重定向,它将标准错误 重定向到标准输出 的位置,因为标准输出已经被重定向到了 app.log,所以标准错误也会被写入到 app.log 中。2 代表标准错误,&1 代表标准输出。

如何管理

  • 查看进程

    ps aux | grep java

    你会看到你的 Java 进程正在运行。ps 输出的第二列是 PID (Process ID),这是你接下来操作的关键。

  • 停止进程

    Linux下Java如何后台运行?-图2
    (图片来源网络,侵删)
    kill <PID>

    如果程序正常,它会优雅地退出,如果不行,可以使用强制关闭:

    kill -9 <PID>
  • 查看日志

    tail -f app.log

    tail -f 会持续显示文件的最新内容,非常适合监控日志。

优点

  • 简单,无需额外安装任何软件。
  • 所有 Linux/Unix 系统都内置。

缺点

  • 不是守护进程:如果你直接关机或重启,程序不会自动重启。
  • 管理不便kill 命令不够优雅,无法方便地查看状态、重启或处理日志轮转。
  • 会话组问题:如果用户退出登录,nohup 进程可能会变成孤儿进程,虽然能运行,但管理起来比较麻烦。

使用 screentmux (适合交互式后台任务)

screentmux 是终端复用工具,你可以创建一个“会话”,在会话中启动程序,detach(分离)会话,即使你关闭了终端,会话和其中的程序依然在后台运行。

使用 screen (以 screen 为例)

  1. 创建一个新会话并进入

    screen -S my_app_session

    你会进入一个新的、干净的终端环境。

  2. 在会话中启动你的 Java 程序

    java -jar your-app.jar

    程序会直接在这个会话中运行,输出会显示在终端上。

  3. 分离会话 按下 Ctrl + A,然后按下 D,你会返回到原来的终端,并看到类似 [detached from ...] 的提示,你的 Java 程序现在正在后台运行。

  4. 重新附加到会话 如果你想查看程序的实时输出或进行交互:

    screen -r my_app_session

    你会重新回到那个会话。

  5. 杀死会话 如果你想完全结束会话和其中的程序:

    screen -X -S my_app_session quit

优点

  • 可以随时“连接”回后台会话进行交互。
  • 比纯 nohup 更灵活。

缺点

  • 仍然不是一个系统级的守护进程。
  • 如果服务器重启,会话和程序依然会消失。
  • 需要用户手动管理会话。

使用 systemd (最专业、推荐的方式)

systemd 是现代 Linux 发行版(如 CentOS 7+, Ubuntu 16.04+)的默认系统和服务管理器,这是生产环境运行 Java 应用的最佳实践,它能将你的 Java 程序包装成一个系统服务,实现完整的生命周期管理。

步骤

  1. 创建一个服务文件/etc/systemd/system/ 目录下创建一个服务文件,my-app.service

    sudo vim /etc/systemd/system/my-app.service
  2. 编写服务文件内容 将以下内容粘贴到文件中,并根据你的实际情况进行修改。

    [Unit]
    Description=My Awesome Java Application
    After=network.target
    [Service]
    # 替换为你的Java程序运行的用户
    User=myuser
    # 替换为你的Java程序运行的用户组
    Group=myuser
    # JVM启动参数,可以根据需要调整
    # -Xms: 初始堆大小
    # -Xmx: 最大堆大小
    # -Djava.io.tmpdir: 指定临时目录
    Environment="JAVA_OPTS=-Xms512m -Xmx1024m -Djava.io.tmpdir=/var/tmp/my-app"
    # 程序的启动命令
    # ExecStart: 核心启动命令
    # ExecStop: 停止命令
    # ExecReload: 重载命令
    # PIDFile: 记录PID的文件路径
    ExecStart=/usr/bin/java $JAVA_OPTS -jar /path/to/your-app.jar
    ExecStop=/bin/kill -15 $MAINPID
    ExecReload=/bin/kill -HUP $MAINPID
    PIDFile=/var/run/my-app/my-app.pid
    # 自动重启策略
    # on-failure: 当进程非正常退出时(退出码非0)重启
    # always: 总是重启
    Restart=on-failure
    RestartSec=10s
    # 日志管理
    StandardOutput=journal
    StandardError=journal
    [Install]
    WantedBy=multi-user.target

    关键点解释:

    • [Unit]:定义了服务的元数据,比如描述、依赖关系(After=network.target 表示网络启动后再启动此服务)。
    • [Service]:定义了服务的具体行为。
      • User/Group:强烈建议不要用 root 用户运行,使用一个专门的低权限用户。
      • Environment:定义环境变量,如 JAVA_OPTS
      • ExecStart:最核心的命令。务必使用绝对路径
      • PIDFilesystemd 会通过这个文件来跟踪你的进程,实现精确的停止和重载。
      • Restart=on-failure:这是生产环境的关键,当程序崩溃时,systemd 会自动帮你重启它。
      • StandardOutput/StandardError=journal:将日志输出到 systemd 的日志中心 journald,而不是文件,你可以用 journalctl 命令统一查看和管理。
    • [Install]:定义了如何安装这个服务。WantedBy=multi-user.target 表示在系统进入多用户模式(也就是正常启动后)时自动启动。
  3. 创建必要的目录和设置权限

    # 创建PID文件目录
    sudo mkdir -p /var/run/my-app/
    # 将目录所有权分配给服务文件中指定的用户
    sudo chown myuser:myuser /var/run/my-app/
  4. 管理服务

    • 重新加载 systemd 配置 (新建或修改服务文件后必须执行):
      sudo systemctl daemon-reload
    • 启动服务:
      sudo systemctl start my-app
    • 停止服务:
      sudo systemctl stop my-app
    • 重启服务:
      sudo systemctl restart my-app
    • 查看服务状态:
      sudo systemctl status my-app

      你会看到服务的运行状态、CPU/内存占用、最近日志等信息。

    • 设置开机自启:
      sudo systemctl enable my-app
    • 禁用开机自启:
      sudo systemctl disable my-app
    • 查看日志:
      # 查看实时日志
      sudo journalctl -u my-app -f
      # 查看最近的100行日志
      sudo journalctl -u my-app --lines 100

优点

  • 专业级管理:启动、停止、重启、状态查看、开机自启等功能一应俱全。
  • 高可靠性:自动重启机制确保服务的高可用性。
  • 日志集成:与系统日志 journald 无缝集成,方便统一管理和查询。
  • 资源管理:可以限制服务的 CPU 和内存使用。
  • 最佳实践:是所有现代 Linux 服务器上运行服务的标准方式。

缺点

  • 配置比前两种方法稍复杂,需要理解 systemd 的配置文件格式。
  • 仅适用于支持 systemd 的现代 Linux 系统。

使用第三方工具 (如 PM2)

如果你的应用更偏向于 Node.js,但也可以用于 Java,或者你想要一个更通用的进程管理器,可以考虑 PM2,对于纯 Java 服务,systemd 通常是更优选择。

优点

  • 跨平台(Linux, macOS, Windows)。
  • 提供丰富的进程管理功能(集群模式、日志管理、监控等)。

缺点

  • 对于 Java 应用来说有些“重量级”,systemd 已经做得很好了。
  • 在系统层面,systemd 仍然是更底层的、更可靠的解决方案。

总结与推荐

方案 优点 缺点 适用场景
nohup & & 极其简单,无需额外工具 管理不便,非守护进程,不健壮 临时任务、快速测试、调试
screen / tmux 可交互,会话可恢复 非守护进程,需手动管理,重启即消失 需要长时间交互的后台任务,如编译、脚本
systemd 专业、健壮、可靠、功能全面 配置稍复杂 生产环境、任何需要长期稳定运行的服务
PM2 跨平台,功能丰富 对 Java 来说可能过重 多语言环境,或已有使用 PM2 的团队

最终建议:

  • 对于学习和临时任务:使用 nohup& 就足够了。
  • 对于需要交互的后台任务:使用 screentmux
  • 对于任何生产环境、正式项目强烈推荐使用 systemd,这是最规范、最稳定、最易于维护的方式,也是现代 Linux 系统的标准做法。
分享:
扫描分享到社交APP
上一篇
下一篇