最后阻塞在守护线程中

发布于 2024-11-25 08:42:36 字数 133 浏览 0 评论 0原文

我知道守护线程中的finally 块不会被执行。但我细致的本性试图理解为什么 JVM 会发生如此特殊的情况,以至于它无法调用此块下的代码。

我认为它在某种程度上与调用堆栈有关,它不应该展开,但不知道如何展开。有人可以解释一下吗? 谢谢。

I know that finally blocks in deamon threads would not be executed. But my meticulous nature tries to understand why and what happens in JVM so special that it could not call the code under this block.

I think that it somehow related to call stack that it whould not unwind, but don't know how. Can someone please shed some light on this.
Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

下壹個目標 2024-12-02 08:42:36

谁说守护线程中的 finally 块不会执行?一般来说,这是正确的。

可能听说过,当 JVM 在 try 执行期间关闭时(或者catch) 块。这是正确的(并且它很容易发生在守护线程上)。

但同样:在正常操作期间,没有任何可以阻止 finally 块在守护线程中正常执行:它们没有以不同的方式处理。

关闭问题很简单:当 JVM 被要求关闭甚至强制关闭时,它可能根本无法执行更多语句。

例如,在 POSIX-y 操作系统上,信号 9 (SIGKILL) 强制应用程序退出,使其没有机会进行任何清理(这就是通常首选信号 15 (SIGTERM) 的原因) 。在这种情况下,JVM 无法执行finally 块,因为操作系统不会让它再运行。

Who says that finally blocks in daemon threads don't execute? This is not true in general.

What you might have heard that a finally block is not guaranteed to be executed when a JVM is shut down during the execution of the try (or catch) block. That is correct (and it can easily happen to daemon threads).

But again: during normal operation, there is nothing that stops finally blocks from executing normally in daemon threads: they are not handled differently.

The shutdown problem is easy: when the JVM is asked to shut down or even forced to shut down, then it may simply not be able to execute any more statements.

For example, on POSIX-y operating systems, signal 9 (SIGKILL) forces an application to quit, giving it no chance to do any cleanup (this is why signal 15 (SIGTERM) is preferred, usually). In this case, the JVM can't execute the finally block, because the OS won't let it run any longer.

娇纵 2024-12-02 08:42:36

如果在执行 try 或 catch 代码时 JVM 退出,则finally 块可能不会执行。
正常关闭 - 当最后一个非守护进程时,会发生这种情况线程退出或当 Runtime.exit()
当线程退出时,JVM 会执行正在运行的线程的清单,并且如果唯一的线程剩下的是守护线程,它会启动有序关闭。当 JVM 停止时,任何剩余的守护线程都会被放弃,finally 块不会被执行,堆栈不会展开,JVM 只是退出。应谨慎使用守护线程,很少有处理活动可以随时安全地放弃,无需清理。特别是,将守护线程用于可能执行任何类型 I/O 的任务是危险的。守护线程最好保留用于“内务处理”任务,例如定期从内存缓存中删除过期条目的后台线程。

最后一个非守护线程退出示例:

public class TestDaemon {
    private static Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    System.out.println("Is alive");
                    Thread.sleep(10);
                    // throw new RuntimeException();
                }
            } catch (Throwable t) {
                t.printStackTrace();
            } finally {
                System.out.println("This will never be executed.");
            }
        }
    };

    public static void main(String[] args) throws InterruptedException {
        Thread daemon = new Thread(runnable);
        daemon.setDaemon(true);
        daemon.start();
        Thread.sleep(100);
        // daemon.stop();
        System.out.println("Last non-daemon thread exits.");
    }
}

输出:

Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive

If the JVM exits while the try or catch code is being executed, then the finally block may not execute.
Normal Shutdown - this occurs either when the last non-daemon thread exits OR when Runtime.exit()
When a thread exits, the JVM performs an inventory of running threads, and if the only threads that are left are daemon threads, it initiates an orderly shutdown. When the JVM halts, any remaining daemon threads are abandoned finally blocks are not executed, stacks are not unwound the JVM just exits. Daemon threads should be used sparingly few processing activities can be safely abandoned at any time with no cleanup. In particular, it is dangerous to use daemon threads for tasks that might perform any sort of I/O. Daemon threads are best saved for "housekeeping" tasks, such as a background thread that periodically removes expired entries from an in-memory cache.

Last non-daemon thread exits example:

public class TestDaemon {
    private static Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    System.out.println("Is alive");
                    Thread.sleep(10);
                    // throw new RuntimeException();
                }
            } catch (Throwable t) {
                t.printStackTrace();
            } finally {
                System.out.println("This will never be executed.");
            }
        }
    };

    public static void main(String[] args) throws InterruptedException {
        Thread daemon = new Thread(runnable);
        daemon.setDaemon(true);
        daemon.start();
        Thread.sleep(100);
        // daemon.stop();
        System.out.println("Last non-daemon thread exits.");
    }
}

Output:

Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive
琴流音 2024-12-02 08:42:36

我创建了两个非守护线程,它们将在其余两个守护线程之前终止。

一个非守护线程等待 20 秒,
一个守护线程等待 40 秒,
一个非守护线程休眠 15 秒,
一个守护线程休眠 30 秒,
一个守护线程休眠 10 秒。在一些守护线程之前终止非守护线程的想法。

结果表明,一旦没有非守护线程处于活动状态,JVM 将立即终止,而不执行守护线程的 Runnable 任务中的剩余语句,即使它们位于finally 块内且不会抛出 InterruptedException。

public class DeamonTest {

    public static void main(String[] args) {
        spawn(40000, Action.wait, true);
        spawn(30000, Action.sleep, true);
        spawn(10000, Action.sleep, true);
        spawn(20000, Action.wait, false);
        spawn(15000, Action.sleep, false);
    }

    enum Action {
        wait, sleep
    }

    private static void spawn(final long time, final Action action,
                              boolean daemon) {
        final Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {

                    Thread thread = Thread.currentThread();
                    try {
                        switch (action) {
                        case wait: {
                            synchronized (this) {

                                System.out.println(thread + " daemon="
                                                   + thread.isDaemon() + ": waiting");
                                wait(time);
                            }
                            break;
                        }
                        case sleep: {

                            System.out.println(thread + " daemon="
                                               + thread.isDaemon() + ": sleeping");
                            Thread.sleep(time);
                        }
                        }
                        System.out.println(thread + " daemon=" + thread.isDaemon()
                                           + ": exiting");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        System.out.println(thread + " daemon=" + thread.isDaemon()
                                           + ": finally exiting");
                    }
                }

            });
        thread.setDaemon(daemon);
        thread.start();
    }
}

I have created two non-daemon threads which will terminate before the rest two daemon threads.

One non-daemon thread wait for 20 sec,
one daemon thread wait for 40 sec,
one non-daemon thread sleep for 15 sec,
one daemon thread sleep for 30 sec,
one daemon thread sleep for 10 sec. The idea to terminate non-daemon threads before some daemon ones.

As the result suggests, the JVM will terminate as soon as there is no non-daemon thread alive, without executing the rest statements in the Runnable tasks of the daemon threads, even if they are inside finally block without throwing InterruptedException.

public class DeamonTest {

    public static void main(String[] args) {
        spawn(40000, Action.wait, true);
        spawn(30000, Action.sleep, true);
        spawn(10000, Action.sleep, true);
        spawn(20000, Action.wait, false);
        spawn(15000, Action.sleep, false);
    }

    enum Action {
        wait, sleep
    }

    private static void spawn(final long time, final Action action,
                              boolean daemon) {
        final Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {

                    Thread thread = Thread.currentThread();
                    try {
                        switch (action) {
                        case wait: {
                            synchronized (this) {

                                System.out.println(thread + " daemon="
                                                   + thread.isDaemon() + ": waiting");
                                wait(time);
                            }
                            break;
                        }
                        case sleep: {

                            System.out.println(thread + " daemon="
                                               + thread.isDaemon() + ": sleeping");
                            Thread.sleep(time);
                        }
                        }
                        System.out.println(thread + " daemon=" + thread.isDaemon()
                                           + ": exiting");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        System.out.println(thread + " daemon=" + thread.isDaemon()
                                           + ": finally exiting");
                    }
                }

            });
        thread.setDaemon(daemon);
        thread.start();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文