gpt4 book ai didi

java - 为什么新的 Java Logger 在这里无法一致工作?

转载 作者:行者123 更新时间:2023-12-02 01:00:42 43 4
gpt4 key购买 nike

请注意大多数其他调用 Logger 调用是如何工作的,以及所有 System.out.println() 是如何工作的,但请有人向我解释为什么 stop()destroy() 中的 >Logger.info() 调用永远不会与日志的其余部分一起打印,因为这些函数显然正在运行! ?对于 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! 🙇‍♂️👋🖖

最佳答案

此问题隐藏在:JDK-8161253 - LogManager$Cleaner() can prevent logging in other shutdown hooks .

每张票:

As a workaround to creating a custom shutdown hook you can create a custom handler and install it on the root logger. The first action of the LogManager$Cleaner is to close all the installed handlers on the logger. Once the cleaner calls the close on the custom handler you can then do one of the following:

  1. 在处理程序内更干净地运行关闭代码。
  2. 使用 Thread API 找到您的自定义关闭 Hook 并加入它。

这是解决方案#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 变得很棘手,因为我们无法确保从一个关闭 Hook 启动了另一个关闭 Hook 。如果您想使用 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);
}
}
}

关于java - 为什么新的 Java Logger 在这里无法一致工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60687511/

43 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com