2026/2/22 13:15:09
网站建设
项目流程
网站seo三要素,分析竞争对手网站,杭州马家厨房食品有限公司成立,有网站做点什么好SpringBoot 中有一种方式可以优雅地关闭应用程序。#xff08;优雅停机是指关闭应用程序时#xff0c;在规定的超时时间范围内#xff0c;允许进行中的请求完成#xff0c;拒绝新的请求进入。 这将使应用在请求处理方面保持一致#xff0c;即没有未处理请求#xff0c;每…SpringBoot 中有一种方式可以优雅地关闭应用程序。优雅停机是指关闭应用程序时在规定的超时时间范围内允许进行中的请求完成拒绝新的请求进入。 这将使应用在请求处理方面保持一致即没有未处理请求每一个请求都被处理完成或拒绝配置如下yml server: port: 8888 shutdown: graceful management: endpoint: shutdown: enabled: true endpoints: web: exposure: include: shutdownxml dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency现象直接调用 localhost:8888/actuator/shutdown 即可关闭应用程序。但是在调用某个业务后再调用 shutdown 的 api发现实际 shutdown 确实在执行但是最终并没有把 pid 给 kill 掉应用程序依然在运行。第一怀疑就是认为这个程序执行后还有什么资源没有被关闭掉导致 springboot 认为应用程序还在运行从而没有执行关闭操作。排查过程执行脚本shell 生成线程快照 jstack -l pid threads.txt # 查询非守护进程因为非守护线程会阻止 JVM 退出 -v 表示反向排除 grep -n threads2.txt | grep -v daemon所有线程信息非守护线程信息在里面发现了一段 关于 pool-X-thread-Y的线程信息这个 ThreadPoolExecutor 出来的线程处于等待中其他的都是额外框架的线程信息或者 jvm 的只有pool-X-thread-Y属于额外的。less pool-4-thread-1 #230 prio5 os_prio31 cpu0.21ms elapsed252.08s tid0x00000001642cf800 nid0x9a07 waiting on condition [0x000000017aaf6000] java.lang.Thread.State: WAITING (parking) at jdk.internal.misc.Unsafe.park(java.base17.0.13/Native Method) - parking to wait for 0x0000000701e8af30 (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(java.base17.0.13/LockSupport.java:341) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(java.base17.0.13/AbstractQueuedSynchronizer.java:506) at java.util.concurrent.ForkJoinPool.unmanagedBlock(java.base17.0.13/ForkJoinPool.java:3465) at java.util.concurrent.ForkJoinPool.managedBlock(java.base17.0.13/ForkJoinPool.java:3436) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base17.0.13/AbstractQueuedSynchronizer.java:1630) at java.util.concurrent.ArrayBlockingQueue.take(java.base17.0.13/ArrayBlockingQueue.java:420) at java.util.concurrent.ThreadPoolExecutor.getTask(java.base17.0.13/ThreadPoolExecutor.java:1062) at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base17.0.13/ThreadPoolExecutor.java:1122) at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base17.0.13/ThreadPoolExecutor.java:635) at java.lang.Thread.run(java.base17.0.13/Thread.java:840) Locked ownable synchronizers: - NoneThreadPoolExecutor 默认线程名称源码有了这个排查方向去项目里面查找关于ThreadPoolExecutor的代码。最终发现一句关于线程池的声明代码。从代码来看虽然 XxxConfig 类上加了 Configuration 注解受到 spring 管理但是 XXX_EXECUTOR 这个线程池是静态变量 并没有受到 spring 管理所以 springboot 在执行 shutdown 的时候并不会关闭这个线程池导致应用程序没有被关闭。java Configuration public class XxxConfig { public static final ThreadPoolExecutor XXX_EXECUTOR new ThreadPoolExecutor(20, 20, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(10000), new ThreadPoolExecutor.CallerRunsPolicy()); }最终解决方案建议将 XXX_EXECUTOR 这个线程池改为 spring 管理的 bean如下所示java Configuration public class XxxConfig { Bean(xxxExecutor) public ThreadPoolExecutor xxxExecutor() { //示例 demo return new ThreadPoolExecutor(20, 20, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(10000), new ThreadPoolExecutor.CallerRunsPolicy()); } }