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

- 脱离终端:程序启动后,即使你关闭了 SSH 终端窗口,程序也应该继续运行。
- 输入输出重定向:程序在后台运行时,它的标准输入、标准输出和标准错误需要被妥善处理,否则它们可能会阻塞程序或产生大量无用的日志文件。
- 进程管理:能够方便地启动、停止、查看状态和重启程序。
- 守护进程化:理想的 Java 后台服务应该像一个系统守护进程一样,在系统启动时自动启动,在系统关闭时自动关闭。
使用 nohup 和 & (最简单,适合临时任务)
这是最基础的后台运行方式,非常适合用来临时启动一个程序,或者用于测试。
命令
nohup java -jar your-app.jar > app.log 2>&1 &
命令分解
java -jar your-app.jar:这是你的 Java 程序启动命令。&:这个符号的作用是将命令在后台执行,你执行完命令后,终端会立即返回,不会阻塞。nohup:no 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),这是你接下来操作的关键。 -
停止进程:
(图片来源网络,侵删)kill <PID>
如果程序正常,它会优雅地退出,如果不行,可以使用强制关闭:
kill -9 <PID>
-
查看日志:
tail -f app.log
tail -f会持续显示文件的最新内容,非常适合监控日志。
优点
- 简单,无需额外安装任何软件。
- 所有 Linux/Unix 系统都内置。
缺点
- 不是守护进程:如果你直接关机或重启,程序不会自动重启。
- 管理不便:
kill命令不够优雅,无法方便地查看状态、重启或处理日志轮转。 - 会话组问题:如果用户退出登录,
nohup进程可能会变成孤儿进程,虽然能运行,但管理起来比较麻烦。
使用 screen 或 tmux (适合交互式后台任务)
screen 和 tmux 是终端复用工具,你可以创建一个“会话”,在会话中启动程序,detach(分离)会话,即使你关闭了终端,会话和其中的程序依然在后台运行。
使用 screen (以 screen 为例)
-
创建一个新会话并进入
screen -S my_app_session
你会进入一个新的、干净的终端环境。
-
在会话中启动你的 Java 程序
java -jar your-app.jar
程序会直接在这个会话中运行,输出会显示在终端上。
-
分离会话 按下
Ctrl + A,然后按下D,你会返回到原来的终端,并看到类似[detached from ...]的提示,你的 Java 程序现在正在后台运行。 -
重新附加到会话 如果你想查看程序的实时输出或进行交互:
screen -r my_app_session
你会重新回到那个会话。
-
杀死会话 如果你想完全结束会话和其中的程序:
screen -X -S my_app_session quit
优点
- 可以随时“连接”回后台会话进行交互。
- 比纯
nohup更灵活。
缺点
- 仍然不是一个系统级的守护进程。
- 如果服务器重启,会话和程序依然会消失。
- 需要用户手动管理会话。
使用 systemd (最专业、推荐的方式)
systemd 是现代 Linux 发行版(如 CentOS 7+, Ubuntu 16.04+)的默认系统和服务管理器,这是生产环境运行 Java 应用的最佳实践,它能将你的 Java 程序包装成一个系统服务,实现完整的生命周期管理。
步骤
-
创建一个服务文件 在
/etc/systemd/system/目录下创建一个服务文件,my-app.service。sudo vim /etc/systemd/system/my-app.service
-
编写服务文件内容 将以下内容粘贴到文件中,并根据你的实际情况进行修改。
[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:最核心的命令。务必使用绝对路径。PIDFile:systemd会通过这个文件来跟踪你的进程,实现精确的停止和重载。Restart=on-failure:这是生产环境的关键,当程序崩溃时,systemd会自动帮你重启它。StandardOutput/StandardError=journal:将日志输出到systemd的日志中心journald,而不是文件,你可以用journalctl命令统一查看和管理。
[Install]:定义了如何安装这个服务。WantedBy=multi-user.target表示在系统进入多用户模式(也就是正常启动后)时自动启动。
-
创建必要的目录和设置权限
# 创建PID文件目录 sudo mkdir -p /var/run/my-app/ # 将目录所有权分配给服务文件中指定的用户 sudo chown myuser:myuser /var/run/my-app/
-
管理服务
- 重新加载 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
- 重新加载 systemd 配置 (新建或修改服务文件后必须执行):
优点
- 专业级管理:启动、停止、重启、状态查看、开机自启等功能一应俱全。
- 高可靠性:自动重启机制确保服务的高可用性。
- 日志集成:与系统日志
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和&就足够了。 - 对于需要交互的后台任务:使用
screen或tmux。 - 对于任何生产环境、正式项目:强烈推荐使用
systemd,这是最规范、最稳定、最易于维护的方式,也是现代 Linux 系统的标准做法。
