Spring Boot @PostConstruct 报错后程序没有退出

Sping Boot jcmd JVM About 10,783 words

期望场景

Kubernetes中,Spring Boot容器在@PostConstruct中进行远程调用拉取配置,如果拉取失败则抛出异常,程序结束运行,Pod重新启动。

程序不退出排查

使用jcmd <pid> Thread.print命令查看线程情况。

jcmd 1 Thread.print -l -e

输出

❯ jcmd 1 Thread.print -l -e
1:
2024-12-12 09:42:41
Full thread dump OpenJDK 64-Bit Server VM (21.0.1+12-LTS mixed mode, sharing):

Threads class SMR info:
_java_thread_list=0x000060000203c4c0, length=14, elements={
0x000000013a86ce00, 0x000000014985f000, 0x000000014985f800, 0x0000000149860000,
0x0000000149860800, 0x0000000149861000, 0x0000000149867800, 0x000000013980b200,
0x0000000149870000, 0x0000000149888800, 0x000000013a3e9a00, 0x000000013a71c200,
0x00000001320f2400, 0x0000000133008200
}

"Reference Handler" #9 [23299] daemon prio=10 os_prio=31 cpu=5.37ms elapsed=23.48s allocated=22248B defined_classes=0 tid=0x000000013a86ce00 nid=23299 waiting on condition  [0x000000016c7e2000]
   java.lang.Thread.State: RUNNABLE
    at java.lang.ref.Reference.waitForReferencePendingList(java.base@21.0.1/Native Method)
    at java.lang.ref.Reference.processPendingReferences(java.base@21.0.1/Reference.java:246)
    at java.lang.ref.Reference$ReferenceHandler.run(java.base@21.0.1/Reference.java:208)

   Locked ownable synchronizers:
    - None

"Finalizer" #10 [23555] daemon prio=8 os_prio=31 cpu=0.56ms elapsed=23.48s allocated=106K defined_classes=1 tid=0x000000014985f000 nid=23555 in Object.wait()  [0x000000016c9ee000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait0(java.base@21.0.1/Native Method)
    - waiting on <0x0000000600130928> (a java.lang.ref.NativeReferenceQueue$Lock)
    at java.lang.Object.wait(java.base@21.0.1/Object.java:366)
    at java.lang.Object.wait(java.base@21.0.1/Object.java:339)
    at java.lang.ref.NativeReferenceQueue.await(java.base@21.0.1/NativeReferenceQueue.java:48)
    at java.lang.ref.ReferenceQueue.remove0(java.base@21.0.1/ReferenceQueue.java:158)
    at java.lang.ref.NativeReferenceQueue.remove(java.base@21.0.1/NativeReferenceQueue.java:89)
    - locked <0x0000000600130928> (a java.lang.ref.NativeReferenceQueue$Lock)
    at java.lang.ref.Finalizer$FinalizerThread.run(java.base@21.0.1/Finalizer.java:173)

   Locked ownable synchronizers:
    - None

"Signal Dispatcher" #11 [30979] daemon prio=9 os_prio=31 cpu=0.30ms elapsed=23.48s allocated=272B defined_classes=0 tid=0x000000014985f800 nid=30979 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Service Thread" #12 [30467] daemon prio=9 os_prio=31 cpu=0.98ms elapsed=23.48s allocated=0B defined_classes=0 tid=0x0000000149860000 nid=30467 runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Monitor Deflation Thread" #13 [24067] daemon prio=9 os_prio=31 cpu=1.64ms elapsed=23.48s allocated=0B defined_classes=0 tid=0x0000000149860800 nid=24067 runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"C2 CompilerThread0" #14 [24579] daemon prio=9 os_prio=31 cpu=3418.22ms elapsed=23.48s allocated=120B defined_classes=0 tid=0x0000000149861000 nid=24579 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   No compile task

   Locked ownable synchronizers:
    - None

"C1 CompilerThread0" #17 [30211] daemon prio=9 os_prio=31 cpu=976.60ms elapsed=23.48s allocated=17120B defined_classes=0 tid=0x0000000149867800 nid=30211 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   No compile task

   Locked ownable synchronizers:
    - None

"Notification Thread" #18 [25347] daemon prio=9 os_prio=31 cpu=0.04ms elapsed=23.48s allocated=0B defined_classes=0 tid=0x000000013980b200 nid=25347 runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Common-Cleaner" #19 [29955] daemon prio=8 os_prio=31 cpu=1.76ms elapsed=23.48s allocated=1520B defined_classes=0 tid=0x0000000149870000 nid=29955 waiting on condition  [0x000000016d842000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at jdk.internal.misc.Unsafe.park(java.base@21.0.1/Native Method)
    - parking to wait for  <0x000000060012a6c8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.parkNanos(java.base@21.0.1/LockSupport.java:269)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@21.0.1/AbstractQueuedSynchronizer.java:1847)
    at java.lang.ref.ReferenceQueue.await(java.base@21.0.1/ReferenceQueue.java:71)
    at java.lang.ref.ReferenceQueue.remove0(java.base@21.0.1/ReferenceQueue.java:143)
    at java.lang.ref.ReferenceQueue.remove(java.base@21.0.1/ReferenceQueue.java:218)
    at jdk.internal.ref.CleanerImpl.run(java.base@21.0.1/CleanerImpl.java:140)
    at java.lang.Thread.runWith(java.base@21.0.1/Thread.java:1596)
    at java.lang.Thread.run(java.base@21.0.1/Thread.java:1583)
    at jdk.internal.misc.InnocuousThread.run(java.base@21.0.1/InnocuousThread.java:186)

   Locked ownable synchronizers:
    - None

"Cleaner-0" #20 [26115] daemon prio=8 os_prio=31 cpu=6.90ms elapsed=23.42s allocated=11488B defined_classes=0 tid=0x0000000149888800 nid=26115 waiting on condition  [0x000000016da4e000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at jdk.internal.misc.Unsafe.park(java.base@21.0.1/Native Method)
    - parking to wait for  <0x0000000600136d80> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.parkNanos(java.base@21.0.1/LockSupport.java:269)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@21.0.1/AbstractQueuedSynchronizer.java:1847)
    at java.lang.ref.ReferenceQueue.await(java.base@21.0.1/ReferenceQueue.java:71)
    at java.lang.ref.ReferenceQueue.remove0(java.base@21.0.1/ReferenceQueue.java:143)
    at java.lang.ref.ReferenceQueue.remove(java.base@21.0.1/ReferenceQueue.java:218)
    at jdk.internal.ref.CleanerImpl.run(java.base@21.0.1/CleanerImpl.java:140)
    at java.lang.Thread.runWith(java.base@21.0.1/Thread.java:1596)
    at java.lang.Thread.run(java.base@21.0.1/Thread.java:1583)
    at jdk.internal.misc.InnocuousThread.run(java.base@21.0.1/InnocuousThread.java:186)

   Locked ownable synchronizers:
    - None

"Thread-2" #38 [41219] prio=5 os_prio=31 cpu=2.83ms elapsed=20.27s allocated=1512B defined_classes=0 tid=0x000000013a3e9a00 nid=41219 waiting on condition  [0x000000016f4ea000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep0(java.base@21.0.1/Native Method)
    at java.lang.Thread.sleep(java.base@21.0.1/Thread.java:509)
    at org.apache.commons.io.monitor.FileAlterationMonitor.run(FileAlterationMonitor.java:214)
    at java.lang.Thread.runWith(java.base@21.0.1/Thread.java:1596)
    at java.lang.Thread.run(java.base@21.0.1/Thread.java:1583)

   Locked ownable synchronizers:
    - None

"Thread-3" #39 [33795] prio=5 os_prio=31 cpu=1.53ms elapsed=20.27s allocated=1512B defined_classes=0 tid=0x000000013a71c200 nid=33795 waiting on condition  [0x000000016f6f6000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep0(java.base@21.0.1/Native Method)
    at java.lang.Thread.sleep(java.base@21.0.1/Thread.java:509)
    at org.apache.commons.io.monitor.FileAlterationMonitor.run(FileAlterationMonitor.java:214)
    at java.lang.Thread.runWith(java.base@21.0.1/Thread.java:1596)
    at java.lang.Thread.run(java.base@21.0.1/Thread.java:1583)

   Locked ownable synchronizers:
    - None

"DestroyJavaVM" #40 [8707] prio=5 os_prio=31 cpu=2996.58ms elapsed=19.74s allocated=272B defined_classes=0 tid=0x00000001320f2400 nid=8707 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"Attach Listener" #41 [32519] daemon prio=9 os_prio=31 cpu=1.01ms elapsed=0.11s allocated=0B defined_classes=0 tid=0x0000000133008200 nid=32519 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
    - None

"VM Thread" os_prio=31 cpu=18.81ms elapsed=23.49s tid=0x0000000149709260 nid=18947 runnable

"GC Thread#0" os_prio=31 cpu=22.15ms elapsed=23.49s tid=0x0000000149607140 nid=13315 runnable

"GC Thread#1" os_prio=31 cpu=29.99ms elapsed=23.31s tid=0x0000000149716410 nid=26371 runnable

"GC Thread#2" os_prio=31 cpu=35.73ms elapsed=23.31s tid=0x0000000149716980 nid=26627 runnable

"GC Thread#3" os_prio=31 cpu=32.03ms elapsed=23.31s tid=0x0000000149716ef0 nid=27139 runnable

"GC Thread#4" os_prio=31 cpu=28.83ms elapsed=23.31s tid=0x0000000149717460 nid=27651 runnable

"GC Thread#5" os_prio=31 cpu=19.61ms elapsed=23.31s tid=0x0000000149717dc0 nid=28931 runnable

"GC Thread#6" os_prio=31 cpu=33.41ms elapsed=23.31s tid=0x0000000149718720 nid=28419 runnable

"GC Thread#7" os_prio=31 cpu=23.39ms elapsed=23.31s tid=0x0000000149719080 nid=28163 runnable

"GC Thread#8" os_prio=31 cpu=28.70ms elapsed=23.31s tid=0x00000001497199e0 nid=43267 runnable

"G1 Main Marker" os_prio=31 cpu=0.25ms elapsed=23.49s tid=0x00000001496078e0 nid=13827 runnable

"G1 Conc#0" os_prio=31 cpu=21.33ms elapsed=23.49s tid=0x0000000149608250 nid=16643 runnable

"G1 Conc#1" os_prio=31 cpu=22.77ms elapsed=22.21s tid=0x00000001497d4800 nid=42247 runnable

"G1 Refine#0" os_prio=31 cpu=13.11ms elapsed=23.49s tid=0x000000013a85c200 nid=17155 runnable

"G1 Service" os_prio=31 cpu=4.85ms elapsed=23.49s tid=0x0000000149706040 nid=17667 runnable

"VM Periodic Task Thread" os_prio=31 cpu=9.68ms elapsed=23.49s tid=0x0000000149609810 nid=20995 waiting on condition

JNI global refs: 20, weak refs: 0

原因

ApacheFileAlterationMonitor文件观察器启动的线程是非守护线程,一直没有退出,所以导致JVM无法退出。

此处有三个线程都是非守护线程,都sleep了。

public final class FileAlterationMonitor implements Runnable {

    private final long interval;

    public FileAlterationMonitor() {
        this(10000);
    }

    @Override
    public void run() {
        while (running) {
            for (final FileAlterationObserver observer : observers) {
                observer.checkAndNotify();
            }
            if (!running) {
                break;
            }
            try {
                Thread.sleep(interval);
            } catch (final InterruptedException ignored) {
                // ignore
            }
        }
    }
}

解决方法

FileAlterationMonitor提供设置线程工厂的方法,将线程工厂生产的线程都指定为守护线程即可。

FileAlterationMonitor monitor = new FileAlterationMonitor();
monitor.setThreadFactory(r -> {
            Thread thread = new Thread(r);
            thread.setDaemon(true);
            return thread;
        });

守护线程和非守护线程区别

当主线程退出时,会等所有非守护线程退出后再结束整个JVM,但不会关注守护线程是否运行完成。(强制退出kill -9不再讨论范围内)

垃圾回收线程就是守护线程。

Views: 12 · Posted: 2024-12-26

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb/LiteNote

扫描下方二维码关注公众号和小程序↓↓↓

扫描下方二维码关注公众号和小程序↓↓↓


Today On History
Browsing Refresh