线程池将守护线程转换成用户线程导致的tomcat shutdown失败

现象

上线过程中出现调用tomcat的shutdown.sh 卡住导致tomcat无法停止的情况。 执行了tomcat的shutdown脚本后,java进程仍然存在。其实无法停止不是tomcat问题,是应用有问题,否则可以跑一个空tomcat,保证shutdown百分之百生效。

先说一下tomcat的大概关闭过程:

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

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

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

资料

Java的线程分为两种:User Thread(用户线程)、DaemonThread(守护线程)。

只要当前JVM实例中尚存任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束是,守护线程随着JVM一同结束工作,Daemon作用是为其他线程提供便利服务,守护线程最典型的应用就是GC(垃圾回收器),他就是一个很称职的守护者。

User和Daemon两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果 User Thread已经全部退出运行了,只剩下Daemon Thread存在了,虚拟机也就退出了。 因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行程序的必要了。

过程

  • 使用工具查看调用shutdown卡住状态的JVM状态:jvisualvm
  • 选择线程tab 然后点击dump线程 image.png

如图: 守护线程会在线程名之后有daemon标识,那么找到现在没有daemon标识的线程:pool-2-thread-1,可以看到来源是一个ScheduledThreadPoolExecutor,说明我们在项目代码中用到了线程池。且由于线程池将守护线程转换成用户线程,导致tomcat无法停止(因为还有用户线程在运行中)

解决

  • 不使用线程池--这不科学
  • 避免线程池将守护线程转换成用户线程
package com.lagou.pard.agent.boot;

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class DefaultNamedThreadFactory implements ThreadFactory {
    private static final AtomicInteger BOOT_SERVICE_SEQ = new AtomicInteger(0);
    private final AtomicInteger threadSeq = new AtomicInteger(0);
    private final String namePrefix;
    public DefaultNamedThreadFactory(String name) {
        namePrefix = "XXX-" + BOOT_SERVICE_SEQ.incrementAndGet() + "-" + name + "-";
    }
    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r,namePrefix + threadSeq.getAndIncrement());
        t.setDaemon(true);
        return t;
    }
}

然后在初始化地方使用:

ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new DefaultNamedThreadFactory("Name"));

其实最重要的一句就是t.setDaemon(true);,设置守护线程。

参考:http://www.importnew.com/26834.html

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×