开发者社区> 问答> 正文

为什么新的Java Logger在这里无法正常工作?

请注意其他大多数调用是如何Logger工作的,以及所有这些System.out.println()工作如何,但是请有人向我解释为什么Logger.info()传入stop()和传入的调用destroy()永远不会与其余日志一起打印,因为这些功能显然正在运行!使用java12,即使destroy()没有显示。这是一个错误吗,我使用它很奇怪吗?

package test;
import java.util.logging.Logger;

public class Test {
    private static Logger LOGGER = Logger.getLogger(Test.class.getCanonicalName());

    public static void main(String[] args) {
        System.out.println("main()");
        LOGGER.info("main()");
        new Test();
    }

    private Test() {
        LOGGER.info("Test()");
        System.out.println("Test()");
        Runtime.getRuntime().addShutdownHook(new ShutdownThread());
    }

    public void shutdown() throws Exception {
        LOGGER.info("shutdown()");
        System.out.println("shutdown()");
        stop();
        destroy();
    }

    public void stop() throws Exception {
        LOGGER.info("stop()");
        System.out.println("stop()");
    }

    public void destroy() {
        LOGGER.info("destroy()");
        System.out.println("destroy()");
    }

    class ShutdownThread extends Thread {
        ShutdownThread() {
            super("app-shutdown-hook");
        }

        @Override
        public void run() {
            try {
                shutdown();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("Bye! ‍♂️");
        }
    }
}

Java 10和Java 11(OpenJDK)的输出:

main()
Mar 14, 2020 1:53:59 PM test.Test main
INFO: main()
Mar 14, 2020 1:53:59 PM test.Test <init>
INFO: Test()
Test()
Mar 14, 2020 1:53:59 PM test.Test shutdown
INFO: shutdown()
shutdown()
stop()
destroy()
Bye! ‍♂️

使用Java 12(OpenJDK)的输出:

main()
Mar 14, 2020 2:17:13 PM test.Test main
INFO: main()
Mar 14, 2020 2:17:13 PM test.Test <init>
INFO: Test()
Test()
shutdown()
stop()
destroy()
Bye! ‍♂️

问题来源:Stack Overflow

展开
收起
montos 2020-03-25 21:03:25 749 0
1 条回答
写回答
取消 提交回答
  • 该问题在以下文章中涉及:JDK-8161253-LogManager $ Cleaner()可以防止登录其他关闭挂钩

    每张票:

    作为创建自定义关机钩子的一种解决方法,您可以创建一个自定义处理程序并将其安装在根记录器上。LogManager $ Cleaner的第一步是关闭记录器上所有已安装的处理程序。清理程序调用自定义处理程序的关闭后,您可以执行以下操作之一:

    让清洁程序在处理程序中运行关闭代码。 使用Thread API查找您的自定义关机钩子,然后将其加入。 这是解决方案1:

    import java.util.logging.Handler;
    import java.util.logging.LogRecord;
    import java.util.logging.Logger;
    
    public class Test {
        private static Logger LOGGER = Logger.getLogger(Test.class.getCanonicalName());
    
        public static void main(String[] args) {
            System.out.println("main()");
            LOGGER.info("main()");
            new Test();
        }
    
        private Test() {
            LOGGER.info("Test()");
            System.out.println("Test()");
            addShutdownHandler();
        }
    
        private void addShutdownHandler() {
            Logger root = Logger.getLogger("");
            Handler[] handlers = root.getHandlers();
    
            for(Handler h : handlers) {
                if (h.getClass() == ShutdownHandler.class) {
                    return;
                }
            }
    
            for(Handler h : handlers) {
                root.removeHandler(h);
            }
    
            root.addHandler(new ShutdownHandler());
    
            for(Handler h : handlers) {
                root.addHandler(h);
            }
        }
    
        public void shutdown() throws Exception {
            LOGGER.info("shutdown()");
            System.out.println("shutdown()");
            stop();
            destroy();
        }
    
        public void stop() throws Exception {
            LOGGER.info("stop()");
            System.out.println("stop()");
        }
    
        public void destroy() {
            LOGGER.info("destroy()");
            System.out.println("destroy()");
        }
    
        class ShutdownHandler extends Handler {
            ShutdownHandler() {
            }
    
            @Override
            public void close() {
                final Thread t = Thread.currentThread();
                final String old = t.getName();
                t.setName("app-shutdown-hook");
                try {
                    shutdown();
                    System.out.println("Bye! ‍♂️");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    t.setName(old);
                }
            }
    
            @Override
            public void flush() {
            }
    
            @Override
            public void publish(LogRecord r) {
                isLoggable(r);
            }
        }
    }
    

    解决方案2变得棘手,因为我们无法确保从关闭挂钩中启动了另一个关闭挂钩。如果要使用Thread :: join,这意味着需要额外的编码。因此,要解决此问题,我们仅使用Future API:

    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    import java.util.logging.ErrorManager;
    import java.util.logging.Handler;
    import java.util.logging.LogRecord;
    import java.util.logging.Logger;
    
    public class Test {
        private static Logger LOGGER = Logger.getLogger(Test.class.getCanonicalName());
    
        public static void main(String[] args) {
            System.out.println("main()");
            LOGGER.info("main()");
            new Test();
        }
    
        private Test() {
            LOGGER.info("Test()");
            System.out.println("Test()");
            addShutdownHandler();
        }
    
        private void addShutdownHandler() {
            Logger root = Logger.getLogger("");
            Handler[] handlers = root.getHandlers();
    
            for(Handler h : handlers) {
                if (h.getClass() == CleanerJoin.class) {
                    return;
                }
            }
    
            for(Handler h : handlers) {
                root.removeHandler(h);
            }
    
            root.addHandler(new CleanerJoin());
    
            for(Handler h : handlers) {
                root.addHandler(h);
            }
        }
    
        public void shutdown() throws Exception {
            LOGGER.info("shutdown()");
            System.out.println("shutdown()");
            stop();
            destroy();
        }
    
        public void stop() throws Exception {
            LOGGER.info("stop()");
            System.out.println("stop()");
        }
    
        public void destroy() {
            LOGGER.info("destroy()");
            System.out.println("destroy()");
        }
    
        class ShutdownTask implements Callable<Void> {
            ShutdownTask() {
            }
    
            @Override
            public Void call() throws Exception {
                shutdown();
                System.out.println("Bye! ‍♂️");
                return null;
            }
        }
    
        class CleanerJoin extends Handler {
            private final FutureTask<Void> sdt = new FutureTask<>(new ShutdownTask());
    
            CleanerJoin() {
                Runtime.getRuntime().addShutdownHook(new Thread(sdt, "app-shutdown-hook"));
            }
    
    
            @Override
            public void close() {
                boolean interrupted = false;
                try {
                    for(;;) {
                        try { //Could use LogManager to lookup timeout values and use a timed join.
                            sdt.get();
                            break;
                        } catch (ExecutionException e) {
                            reportError("Shutdown hook failed.", e, ErrorManager.CLOSE_FAILURE);
                            break;
                        } catch (InterruptedException retry) {
                            interrupted = true;
                        }
                    }
                } finally {
                    if (interrupted) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
    
            @Override
            public void flush() {
            }
    
            @Override
            public void publish(LogRecord r) {
                isLoggable(r);
            }
        }
    }
    

    回答来源:Stack Overflow

    2020-03-25 21:04:34
    赞同 展开评论 打赏
问答分类:
问答标签:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
Spring Cloud Alibaba - 重新定义 Java Cloud-Native 立即下载
The Reactive Cloud Native Arch 立即下载
JAVA开发手册1.5.0 立即下载