【问题标题】:finally block in daemon threadfinally 在守护线程中阻塞
【发布时间】:2011-10-07 15:44:34
【问题描述】:

我知道在守护线程中的 finally 块不会被执行。但是我一丝不苟的天性试图理解为什么在 JVM 中发生了什么以及发生了什么如此特殊以至于它无法调用此块下的代码。

我认为它在某种程度上与调用堆栈有关,它不会展开,但不知道如何展开。有人可以对此有所了解。 谢谢。

【问题讨论】:

标签: java daemon finally


【解决方案1】:

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

可能听说过finally 块在执行try(或catch)块期间关闭JVM 时不能保证执行。这是正确的(守护线程很容易发生这种情况)。

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

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

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

【讨论】:

  • 关于最后的判决。这是否意味着不仅守护线程而且在这种情况下所有线程都不能执行 finally 子句?
  • 是的,您不能指望在这些情况下运行任何特定代码。它与计算机的 turbibg 相似(当然,它只影响一个进程)。
【解决方案2】:

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.

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

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

【讨论】:

    【解决方案3】:

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

    一个非守护线程等待 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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多