Java:在finalize方法上写入文件

时间:2010-05-29 18:32:04

标签: java file writing finalize

在我的理解中,单个对象只有在应用程序即将终止时才会销毁。所以在C ++中我编写了一个Singleton类来记录我的应用程序,在Singleton logger的析构函数中,我记录了我的应用程序终止时的时间。事情在C ++中完美运作。


现在我想在Java中使用相同的记录器,因为在java中没有析构函数,所以我为该单例记录器实现了finalize方法。但似乎finalize方法实际上永远不会被调用。 所以,我在我的代码中的某处添加System.runFinalizersOnExit(true);行(虽然我知道它已被弃用)并且每次在应用程序终止之前调用finalize方法。但还是有问题!如果我尝试在finalize方法中写入任何文件,它不起作用,虽然System.out没有任何问题! :(

你们可以帮我解决这个问题吗?以下是我尝试做的示例代码:

Singleton Logger类:

public class MyLogger {
    FileWriter writer;
    private MyLogger() {
        try {
            this.writer = new FileWriter("log.txt");
        }
        catch (IOException ex) {
        }
    }

    public static MyLogger getInstance() {
        return MyLoggerHolder.INSTANCE;
    }

    private static class MyLoggerHolder {
        private static final MyLogger INSTANCE = new MyLogger();
    }

    @Override
    protected void finalize () {
        try {
            super.finalize();
            System.out.println("Here"); //worked correctly.
            this.writer.write(new Date().toString()+System.getProperty("line.separator"));
            this.writer.write("End");
            this.writer.flush(); //does not work!
            this.writer.close();
        }
        catch (Throwable ex) {
        }
    }
    public synchronized void log(String str) {
        try {
            this.writer.write(new Date().toString()+System.getProperty("line.separator"));
            this.writer.write(str+"\n");
            this.writer.flush();
        }
        catch (IOException ex) {
        }
    }
 }

主:

public class Main {
    public static void main(String[] args) {
        System.runFinalizersOnExit(true);
        MyLogger logger = MyLogger.getInstance();
        logger.log("test");
    }
}

6 个答案:

答案 0 :(得分:3)

这是一个奇怪的问题。注意:我不会编写自己的Logging类 - 请查看log4j或其他内容......

如前所述,我真的不会真正使用finalize。

...

根据你的说法,你的目标只是在程序停止时运行一些东西。

我注册了一个shutdownhook而不是......

shutdownhook是一个用户定义的对象,它扩展了Thread类。例如您可以在记录器中定义静态内部类

以下是一个例子:

http://www.crazysquirrel.com/computing/java/basics/java-shutdown-hooks.jspx

这是API文档: http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Runtime.html#addShutdownHook%28java.lang.Thread%29

答案 1 :(得分:2)

Effective Java 2nd Edition:第7项:避免使用终结器

  

终结者是不可预测的,通常是危险的,而且通常是不必要的。它们的使用会导致不稳定的行为,性能不佳和可移植性问题。终结器的有效用途很少,但根据经验,你应该避免使用终结器。

     

[...]声称保证最终确定的唯一方法是System.runFinalizersOnExit及其邪恶双胞胎Runtime.runFinalizersOnExit。这些方法存在致命缺陷,已被弃用。

答案 2 :(得分:2)

正如其他答案所说,使用finalize被认为是不好的做法。当VM关闭时发生某些事情的“官方”方式是使用关闭挂钩

关闭挂钩是您创建的Thread对象,但不启动。你用它注册 Runtime.getRuntime().addShutdownHook(Thread)并在VM关闭时调用它。

答案 3 :(得分:1)

Josh Bloch在他的“Effective Java”一书中写道,在终结者中做任何事都是不好的做法。

您可以选择在关闭应用程序时手动执行此操作:

  • 如果您关闭它(使用System.exit(0)),请在那里调用该代码
  • 如果用户关闭它,请添加一个监听器并在那里调用它。

答案 4 :(得分:0)

除了使用finalize是不安全的事实(因为我确定你已经看到了这个,因为你使用System.runFinalizersOnExit的方法已被弃用)你的finalize方法可能会引发异常/错误。在这种情况下,您的异常/错误会在catch语句中捕获,并且没有任何操作。更好的方法是:

try{
   System.out.println("Here"); //worked correctly.
   this.writer.write(new Date().toString()+System.getProperty("line.separator"));
   this.writer.write("End");
   this.writer.flush(); //does not work!
   this.writer.close();
}
catch(Throwable e){
   //Log or handle the issue
}
finally{
   super.finalize();
}

再说一遍,在Java中使用finalize通常不是一个好习惯,应该避免使用。

答案 5 :(得分:0)

我建议您不要尝试使用自己的日志记录框架,而是查看许多预先存在的Java日志框架之一。我使用log4j,但有很多选择!您将获得更稳定的代码,更少的调试工作,并可能更快的性能。而且,他们不需要棘手的终结者行为。