[英]Java: file write on finalize method
據我了解,單例對象僅在應用程序即將終止時才會銷毀。 因此,在 C++ 中,我編寫了一個 Singleton 類來記錄我的應用程序,並在該 Singleton 記錄器的析構函數中記錄我的應用程序終止的時間。 事情在 C++ 中完美運行。
現在我想在 Java 中使用相同的記錄器,因為在 Java 中沒有析構函數,所以我為該單例記錄器實現了 finalize 方法。 但似乎 finalize 方法實際上從未被調用過。 所以,我添加了System.runFinalizersOnExit(true);
行,在我的代碼中的某處(盡管我知道它已被棄用),並且每次在應用程序終止之前都會調用 finalize 方法。 但是還是有問題! 如果我嘗試在該 finalize 方法中寫入任何文件,它不起作用,盡管 System.out 工作沒有任何問題! :(
你們能幫我解決這個問題嗎? 這是我嘗試做的示例代碼:
單例記錄器類:
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");
}
}
這是那些奇怪的問題之一。 注意:我不會編寫自己的 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
Effective Java 第 2 版:第 7 項:避免使用終結器
終結器是不可預測的,通常是危險的,而且通常是不必要的。 它們的使用會導致行為不穩定、性能不佳和可移植性問題。 終結器幾乎沒有有效用途,[...] 但根據經驗,您應該避免使用終結器。
[...] 唯一聲稱可以保證終結的方法是
System.runFinalizersOnExit
及其邪惡的孿生兄弟Runtime.runFinalizersOnExit
。 這些方法存在致命缺陷,已被棄用。
正如其他答案所說,使用 finalize 被認為是不好的做法。 虛擬機關閉時發生某些事情的“官方”方法是使用關閉掛鈎。
關閉掛鈎是您創建但不啟動的 Thread 對象。 您使用Runtime.getRuntime().addShutdownHook(Thread)注冊它,它將在 VM 關閉時調用。
Josh Bloch 在他的《Effective Java》一書中寫道,在終結器中做任何事情都是不好的做法。
您可以選擇在關閉應用程序時手動執行此操作:
System.exit(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 通常不是一個好習慣,應該避免。
我建議您不要嘗試推出自己的日志框架,而是查看許多預先存在的 Java 日志框架之一。 我使用log4j ,但有很多選擇! 您將獲得更穩定的代碼、更少的調試工作以及可能更快的性能。 而且,它們不需要棘手的終結器行為。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.