如何在后台运行 Java 程序?
1、简介
有时,我们需要在后台运行 Java 程序,即在 SSH 终端关闭后还能继续运行。
2、将 Java 作为后台进程运行
在后台运行 Java 程序的最简单方法之一是在 shell 脚本中使用 &
操作符:
#!/bin/sh
java -jar /web/server.jar &
echo $! > startupApp.pid
最后的 &
可确保进程在后台运行,而 echo $! > startupApp.pid
的作用是获取最后执行的后台命令的 PID(进程 ID),并且重定向输出到 startupApp.pid 文件中。该 PID 可唯一标识运行中的进程,以后可用于进程管理任务,如监控或停止进程。
不过,这种方法有一个缺点。如果我们断开了 SSH 会话,进程仍可能被终止,这会导致后台程序意外停止。
此外,由于进程不是作为服务来管理的,因此更难对其进行正确控制。我们无法像使用 systemd
等正规服务管理器那样轻松查看日志或启动/停止进程。
3、利用 Nohup 保活进程
如果想在断开 SSH 会话后还让后台进程继续执行,那么 nohup
就可以解决这个问题。nohup
(不挂起)可以让进程在关闭会话或终端后继续运行。
nohup
用法如下:
nohup java -jar /web/server.jar > output.log 2>&1 &
echo $! > startupApp.pid
nohup
会让进程继续运行,即使关闭了终端会话。> output.log 2>&1
表示将标准输出和错误输出重定向到一个名为 output.log
的文件中,方便日后检查日志(用于调试)。最后的 &
表示要在后台运行进程。
echo $!> startupApp.pid
将 PID 保存在 startupApp.pid
中,以备将来使用。
如果想杀死进程,可以运行下面的命令:
kill -15 $(cat startupApp.pid)
4、将 Java 程序作为 systemd 服务运行(Linux)
要想长期运行 Java 进程并对其进行更好的管理,可以使用 systemd
将其作为服务来管理。如果使用的是 Linux 服务器,强烈建议采用这种方法。
首先,使用下面的命令创建一个 .service
文件:
sudo nano /etc/systemd/system/myjavaapp.service
接下来,在文件中添加以下内容:
[Unit]
Description: Java Background Service
After=network.target
[Service]
ExecStart=/usr/bin/java -jar /web/server.jar
WorkingDirectory=/web
Restart=always
User=root
StandardOutput=append:/var/log/myjavaapp.log
StandardError=append:/var/log/myjavaapp.err
[Install]
WantedBy=multi-user.target
上述配置文件定义了如何将 Java 应用程序作为后台服务运行。
在 [Unit]
部分,通过 After=network.target
指定只有在网络可用后才能启动。如果我们的 Java 应用程序依赖于互联网或网络服务,这一点就非常重要。
接下来,在 [Service]
部分,要定义 Java 应用程序的运行方式。
ExecStart
告诉 systemd
通过运行 server.jar
来启动 Java 应用程序。WorkingDirectory
定义了服务将从哪个文件夹执行。在本例中,它被设置为 /web
目录。
Restart
可确保在应用程序因任何原因崩溃时,systemd
会自动重启应用程序。
接着,将 User
属性设置为 root
,这意味着服务以 root
用户身份运行。不过,为了提高安全性,一般建议以非 root
用户身份运行服务。
还使用 StandOutput
和 StandardError
属性跟踪日志和错误。这些有助于分析与应用程序相关的问题。
最后,通过 WantedBy=multi-user.target
属性,可以让 Java 应用在系统达到服务的正常工作阶段时自动启动,这样服务就可以在 GUI 渲染之前启动。如果没有这项配置,服务就不知道何时应该自动启动,我们不得不在每次重启后手动启动它。
接下来,需要重新加载 systemd
并启用服务。每当我们创建或修改一项服务后,都需要执行这一步骤,来让 systemd
知晓这些更改。
运行下面的命令,让 systemd
知道我们新添加(或修改)的服务:
sudo systemctl daemon-reload
然后,需要创建一个指向服务文件的符号链接(快捷方式)。系统会将此快捷方式放在一个特殊文件夹中,在启动时检查它,并在 multi-user.target
阶段启动服务。
下面是创建符号链接的命令:
sudo systemctl enable myjavaapp
现在,要启动 Java 应用程序,我们可以重启系统或运行以下命令:
sudo systemctl start myjavaapp
可以使用下面的命令来验证服务是否已启动:
sudo systemctl status myjavaapp
最后,要停止后台进程,可以运行以下命令:
sudo systemctl stop myjavaapp
5、使用 screen 或 tmux 将 Java 作为后台进程运行
与 systemd
或 nohup
不同,screen
和 tmux
允许我们分离(断开)会话而不会停止运行的进程,并在稍后重新连接到我们离开的位置。
简单地说,使用 screen
或 tmux
,我们可以启动 Java 应用程序,关闭笔记本电脑或断开连接,然后再回来查看相同的终端,就像什么都没发生一样,而且应用程序将继续在后台运行。
可以把它想象成 Windows 休眠,但仅限于终端会话。
使用下面的命令:
screen -S myjavaapp java -jar /web/server.jar
要分离,需要按下 Ctrl + A
,同时松开,然后按下 D
:
screen -r myjavaapp
也可以用 tmux
实现类似的结果。下面是相应的命令:
tmux new-session -s myjavaapp 'java -jar /web/server.jar'
若要分离,需要按下 Ctrl + B
,同时松开,然后按下 D
:
tmux attach-session -t myjavaapp
tmux
更现代、更强大、更易用,而 screen
则很简单,足以满足基本需求。不过,大多数 Linux 发行版都预装了 screen
,而我们可能需要单独安装 tmux。
6、总结
本文介绍了如何将 Java 应用作为后台进程运行,以及如何实现在关闭 SSH 终端会话后进程不会终止。
对于简单的情况,nohup
或 &
是非常方便的,但对于生产环境,推荐使用更可靠的 systemd
。screen
和 tmux
等工具为提供了额外的灵活性,即使重启后也能继续执行进程,就像什么都没发生过一样。
Ref:https://www.baeldung.com/java-program-background