在Linux上运行的我的Java程序需要在关闭之前关闭一些文件句柄(实际上是设备),所以我在JVM上添加了一个关闭钩子。但是,我注意到java.util.logging.LogManager
也有一个关闭钩子,它在我关闭之前往往会关闭,这意味着我无法记录关闭过程的任何内容。
有没有办法阻止LogManager安装其关闭钩子,以便我可以在关闭时执行日志记录,然后告诉它在我准备好时清理?
答案 0 :(得分:1)
这更像是一种解决方法......但是......因为我在Linux上运行(这是一个专用于特定系统的程序),所以我最终使用sun.misc.Signal
的信号处理程序。在 JVM运行关闭挂钩之前,信号处理程序将运行(可能它还有自己的信号处理程序启动该进程)。
所以我现在这样做而不是Runtime.getRuntime().addShutdownHook
:
private void installSignalHandlers() {
SignalHandler signalHandler = signal -> shutDown();
Signal.handle(new Signal("INT"), signalHandler);
Signal.handle(new Signal("TERM"), signalHandler);
}
似乎工作得很好;我可以在shutDown
中关闭所有打开的句柄,同时记录仍在运行。
答案 1 :(得分:0)
嗯,您可以使用您创建的类的名称定义系统属性“java.util.logging.manager”。这将允许您使用自己设计的日志记录管理器。
https://docs.oracle.com/javase/8/docs/api/java/util/logging/LogManager.html
我之前从未尝试过这个,所以我不知道它会有多好用,或者它会有多少工作。
答案 2 :(得分:0)
使LogManager清洁线程与关闭挂钩连接或通过安装自定义处理程序直接执行文件清理。更干净的线程将按顺序枚举记录器并尝试关闭附加的处理程序。只要您的处理程序是它尝试关闭的第一个处理程序,您就可以控制清理程序何时执行。
public class ShutdownHandler extends Handler {
public static void main(String[] args) {
install();
}
private static void install() {
LogManager lm = LogManager.getLogManager();
Logger first = null;
ShutdownHandler sh = new ShutdownHandler();
for (;;) {
try {
Enumeration<String> e = lm.getLoggerNames();
while (e.hasMoreElements()) {
first = lm.getLogger(e.nextElement());
if (first != null) {
break;
}
}
break;
} catch (ConcurrentModificationException olderJvm) {
}
}
Logger.getLogger("").addHandler(sh);
if (first != null) {
first.addHandler(sh);
}
}
public ShutdownHandler() {
super.setLevel(Level.ALL);
}
@Override
public void publish(LogRecord record) {
}
@Override
public void flush() {
}
@Override
public void close() throws SecurityException {
if (!Level.OFF.equals(super.getLevel())) {
super.setLevel(Level.OFF);
shutDown();
}
}
private void shutDown() {
System.out.println(this + " shutdown by "
+ Thread.currentThread().getClass().getName());
//Close your files or join with your other shutdown hook.
}
}