请注意其他大多数调用是如何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
该问题在以下文章中涉及: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
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。