Tomcat为什么无法关闭

本文解析了Tomcat关闭脚本执行后Java进程仍存在的原因,主要由于非守护线程未结束。通过jstack命令检查并修改catalina.sh和shutdown.sh文件,确保Tomcat完全关闭。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

执行了tomcat的shutdown脚本后,java进程仍然存在,认为tomcat的关闭脚本不可靠。好吧,其实shutdown.sh无法停止,不是tomcat问题,是应用有问题,否则可以跑一个空tomcat,保证shutdown百分之百生效。

先说一下tomcat的大概关闭过程:
1 停止连接处理线程Accepter,停止接受新的请求
2 关闭tomcat自身的资源,例如各种service,连接器,protocol,container
3 然后tomcat主线程结束了,就是执行BootStrap这个类的线程

这是一个平滑关闭的过程,但是什么时候会导致所谓”tomcat无法关闭”?要更正一点,不是tomcat无法关闭,是执行tomcat的这个jvm无法关闭,这是本质的不同。

最根本的原因是:当前运行tomcat的jvm里还有非deamon的线程没有结束执行,例如被阻塞,或者还在执行任务。这个现象就是tomcat 端口都已经关闭了,但是java进程还在。tomcat的停止只是结束了自己的线程,关闭了自己的资源。但是应用开启的非deamon线程,这个 tomcat是无能为力的。

netstat -ano|grep 8083 /*可以通过此确认tomcat是否已关闭*/

那么JVM什么时候停止?没有非deamon的线程在运行就停止了,或者说应用自身的非deamon线程处理完所有事情结束了自己,jvm就停止了。

那么当发现tomcat停止了,但是ps -ef|grep tomcat进程依然在,如何查看应用那个地方线程是非deamon的呢?

查看办法很简单,执行如下命令:

$JAVA_HOME/bin/jstack  <pid>

例:

[root@localhost bin]# ps -ef|grep tomcat  
root      1513     1  2 23:41 pts/1    00:00:01 /usr/local/share/java/jdk1.6.0_25/bin/java -Djava.util.logging.config.file=/opt/apache-tomcat-6.0.32/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/opt/apache-tomcat-6.0.32/endorsed -classpath /opt/apache-tomcat-6.0.32/bin/bootstrap.jar -Dcatalina.base=/opt/apache-tomcat-6.0.32 -Dcatalina.home=/opt/apache-tomcat-6.0.32 -Djava.io.tmpdir=/opt/apache-tomcat-6.0.32/temp org.apache.catalina.startup.Bootstrap start  
root      1544  1462  0 23:42 pts/1    00:00:00 grep --color=auto tomcat  

可以看到tomcat进展pid为1513,则下面定位到jdk/bin目录,执行jstack1513 查看工程里到底哪里开启的新的非守护线程?

$ cd /home/software/jdk1.7.0_79/bin
$ jstack 1513

调用jstack查看:

[root@localhost bin]# jstack 1513       
2011-07-12 23:44:00
Full thread dump Java HotSpot(TM) Client VM (20.0-b11 mixed mode, sharing):
 
"Attach Listener" daemon prio=10 tid=0xb41d7c00 nid=0x606 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE
 
"TP-Monitor" daemon prio=10 tid=0xb41d6400 nid=0x5fa in Object.wait() [0xb3e0b000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x87143720> (a org.apache.tomcat.util.threads.ThreadPool$MonitorRunnable)
        at org.apache.tomcat.util.threads.ThreadPool$MonitorRunnable.run(ThreadPool.java:565)
        - locked <0x87143720> (a org.apache.tomcat.util.threads.ThreadPool$MonitorRunnable)
        at java.lang.Thread.run(Thread.java:662)
 
"TP-Processor4" daemon prio=10 tid=0xb41d4c00 nid=0x5f9 runnable [0xb3e5c000]
   java.lang.Thread.State: RUNNABLE
        at java.net.PlainSocketImpl.socketAccept(Native Method)
        at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
        - locked <0x87124770> (a java.net.SocksSocketImpl)
        at java.net.ServerSocket.implAccept(ServerSocket.java:462)
        at java.net.ServerSocket.accept(ServerSocket.java:430)
        at org.apache.jk.common.ChannelSocket.accept(ChannelSocket.java:311)
        at org.apache.jk.common.ChannelSocket.acceptConnections(ChannelSocket.java:668)
        at org.apache.jk.common.ChannelSocket$SocketAcceptor.runIt(ChannelSocket.java:879)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690)
        at java.lang.Thread.run(Thread.java:662)

其中看到"Attach Listener" daemon prio=10 tid=0xb41d7c00 nid=0x606 waiting on condition [0x00000000]

   java.lang.Thread.State: RUNNABLE

这行,最前变的"Attach Listener" 是线程名, 紧跟其后的 daemon是线程的守护状态,

其中主线程不是daemon的,所以是这样:

"main" prio=10 tid=0xb6d05000 nid=0x5ea runnable [0xb6ee9000]
   java.lang.Thread.State: RUNNABLE
        at java.net.PlainSocketImpl.socketAccept(Native Method)
        at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
        - locked <0x871644a8> (a java.net.SocksSocketImpl)
        at java.net.ServerSocket.implAccept(ServerSocket.java:462)
        at java.net.ServerSocket.accept(ServerSocket.java:430)
        at org.apache.catalina.core.StandardServer.await(StandardServer.java:431)
        at org.apache.catalina.startup.Catalina.await(Catalina.java:676)
        at org.apache.catalina.startup.Catalina.start(Catalina.java:628)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
        at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)

解决办法:

第一步:修改Tomcat bin目录下catalina.sh文件 ;找到

1

 PRGDIR=`dirname "$PRG"`

这一行,我这里是Tomcat8 是137行,然后在下面追加代码

1

2

3

4

if [ -z "$CATALINA_PID" ]; then

     CATALINA_PID=$PRGDIR/CATALINA_PID

     cat $CATALINA_PID

fi

Tomcat8.png

 

  第二步:修改Tomcat bin目录下shutdown.sh文件;最后一句修改为如下

1

exec "$PRGDIR"/"$EXECUTABLE" stop -force "$@"

即添加了参数 -force

shutdown.sh.png

参考:

https://www.cnblogs.com/nuccch/p/9052692.html

### 可能的原因分析 在 IntelliJ IDEA 中配置 Tomcat 时,如果没有显示 Tomcat Server 的选项,可能是由于以下几个原因: 1. **Tomcat 版本不兼容** 如果使用的 Tomcat 版本过高(例如 Tomcat 10),可能与 IntelliJ IDEA 不完全兼容[^1]。这是因为从 Tomcat 9 开始引入了一些新的特性,而某些 IDE 尚未全面支持。 2. **插件缺失或未启用** IntelliJ IDEA 需要特定的插件来支持 Java EE 和 Servlet 功能。如果这些插件未启用,则可能导致无法识别 Tomcat 服务器。 3. **安装路径错误** 在指定 Tomcat 安装路径时,可能存在路径错误或者选择了非标准的目录结构。确保选择的是完整的 Tomcat 安装根目录。 4. **IDEA 版本过低** 使用较旧版本的 IntelliJ IDEA 可能导致对新版本 Tomcat 的支持不足。建议升级到最新稳定版 IDEA。 --- ### 解决方案 #### 方法一:检查并启用必要的插件 确保以下插件已启用: - `Java Enterprise` 插件(用于支持 JSP/Servlet) - `TomEE Integration` 或其他相关插件 操作步骤如下: 1. 打开 IntelliJ IDEA 设置 (`File -> Settings`)。 2. 导航至 `Plugins` 页面。 3. 搜索并启用上述提到的相关插件。 4. 点击 `Apply` 并重启 IDEA。 #### 方法二:验证 Tomcat 路径 确认所选的 Tomcat 安装路径是否正确。具体方法如下: 1. 前往 `File -> Settings -> Build, Execution, Deployment -> Application Servers`。 2. 添加一个新的 Tomcat 实例,并手动输入其安装路径。 3. 测试该路径是否存在 `bin`, `conf`, 和 `lib` 文件夹。如果缺少任何核心组件,重新下载官方发布的完整包[^3]。 #### 方法三:切换到兼容的 Tomcat 版本 尝试更换为较低版本的 Tomcat(如 Tomcat 8.x 或 9.x)。对于高版本(如 Tomcat 10+),可以考虑使用 Jakarta EE 替代品或其他工具链替代。 #### 方法四:更新 IntelliJ IDEA 如果当前 IDEA 是社区版 (Community Edition),它默认仅提供基础功能而不支持高级企业级服务。推荐升级到 Ultimate Edition 或者单独安装 Apache Maven 来构建项目。 #### 方法五:重置缓存和索引 有时缓存损坏也会引发此类问题。可以通过清理缓存解决: 1. 关闭所有正在运行的实例。 2. 进入菜单栏中的 `File -> Invalidate Caches / Restart...`. 3. 选择 `Invalidate and Restart`. --- ### 示例代码片段 以下是通过脚本方式快速检测 Tomcat 是否正常启动的一个简单例子: ```bash #!/bin/bash TOMCAT_HOME="/path/to/tomcat" if [[ ! -d "$TOMCAT_HOME/bin" ]]; then echo "Error: Invalid TOMCAT_HOME directory." else cd $TOMCAT_HOME/bin && ./startup.sh fi ``` --- ### 总结 以上提供了多种排查思路以及对应的处理措施。通常情况下,按照顺序逐一排除即可定位根本原因。若仍存在问题,请进一步核实日志记录是否有异常提示信息。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值