我编写了一个自定义日志记录类,其行为与类似于System.out或System.err的PrintWriter非常相似。主要区别在于,当调用myLogger.printf("Hello World!\n");
时,数据不会直接写入日志文件,而是写入内部队列,并且此队列仅通过flush();
刷新到输出文件方法。所以使用代码如下:
myLogger.println("Line 1.");
myLogger.println("Line 3.");
myLogger.println("Actually that was Line 2. THIS is Line 3!");
myLogger.flush();
哪个输出应该是这样的:
2016-03-30 15:44:45::389> Line 1.
2016-03-30 15:44:45::390> Line 3.
2016-03-30 15:44:45::395> Actually that was Line 2. THIS is Line 3!
然而,我遇到的问题是用户犯错误。也就是说,他们忘记调用flush()
,他们写入记录器的数据永远不会被转储到文件中,程序关闭时不会刷新数据。
每次通话后我都无法冲洗,因为它首先会破坏写这门课程的目的。让系统管理自动刷新同样会弄巧成拙。
我的想法是在对象的flush()
方法中调用finalize()
,但正如我在此网站上从several other articles读取的那样,我无法保证{{ 1}}将永远被召唤。
为了清楚起见,这就是finalize()
方法的样子:
flush()
那么在程序退出之前确保记录器被刷新的最佳选择是什么?
答案 0 :(得分:3)
您提出了两个不同的问题:如何确保在收集对象之前调用记录器的flush()
方法,以及如何确保在程序之前调用它退出。当您从研究中收集到时,记录器可能会在程序退出之前 收集,因此终结器无法保证将调用该方法。
如果您对VM关闭之前不符合GC条件的记录器感到满意,那么您可以在运行时注册shutdown hook,以刷新记录器。这样的钩子需要保存对记录器的引用,并且运行时将保持对钩子的引用(未启动的Thread
)直到它关闭,因此记录器将保持不适合GC,直到运行时执行其关闭钩子。
答案 1 :(得分:2)
将您的方法放入finalize方法,如下所示:
@Override protected void finalize() throws Throwable {
// TODO Auto-generated method stub
// do some crazy stuff here
super.finalize();
}
这是对象销毁的例子。
要在JVM关闭之前保存数据,请使用shutdown hooks:
public static void main(final String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override public void run() {
// TODO Auto-generated method stub
// do the other crazy stuff in here
super.run();
}
});
}
但两者都不会100%安全使用。 1)您可以在不运行所有终结器的情况下关闭JVM 2)如果通过任务管理器/终止信号终止JVM进程,则不会触发关闭挂钩
答案 2 :(得分:0)
可刷新作家的另一种方法:
TransferQueue<LogItem>
实施take()
。 [阻挡] poll()
[非阻止] 这种方法有几个优点:
LinkedTransferQueue
thread.setDaemon(false)
,这是默认值。