如何在Object被销毁之前调用Method?

时间:2016-03-30 20:56:48

标签: java garbage-collection

我编写了一个自定义日志记录类,其行为与类似于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()

那么在程序退出之前确保记录器被刷新的最佳选择是什么?

3 个答案:

答案 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)

可刷新作家的另一种方法:

  1. 使用TransferQueue<LogItem>实施
  2. 创建单独的日志编写器线程
  3. 在队列中执行take()。 [阻挡]
  4. 打开日志文件,此时可以根据需要执行截断和日志轮换
  5. 撰写项目,用poll() [非阻止]
  6. 排出其他项目
  7. 刷新并关闭日志文件
  8. if(应用程序仍在运行)然后转到3
  9. 这种方法有几个优点:

    • 日志线程将遭受IO和冲洗成本,而不是执行业务逻辑的线程
    • 它是线程安全的,因为只有一个写线程
    • 只要TransferQueue实施,例如LinkedTransferQueue
    • ,日志项提交就是无锁的
    • 记录器线程将使VM保持活动状态,直到写入日志为止,假定为thread.setDaemon(false),这是默认值。