3

In my understanding a singleton object will destroy only when the application is about to terminate. So in C++ I write a Singleton class to log my application and in that Singleton logger's destructor I log the time when my application was terminated. Things worked perfectly in C++.


Now I want to have that same logger in Java, as in java there is no destructor so I implemented the finalize method for that singleton logger. But it seem that finalize method actually never get called. So, I add that System.runFinalizersOnExit(true); line, somewhere in my code (though I know it is deprecated) and that finalize method get called every time before termination of the app. But still there is a problem! If I try to write anything on file in that finalize method, It does not work, though System.out work without any problem! :(

Can you guys help me on this problem? Here is a sample code of what I am try to do:

Singleton Logger Class:

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) {
        }
    }
 }

Main:

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

6 に答える 6

3

これは、それらの興味深い質問の 1 つです。注: 私は独自の Logging クラスを作成しません - log4j などを見てください...

すでに述べたように、私は実際にはファイナライズを使用しません。

...

あなたの言うことから、あなたの目的は、プログラムが停止するときに何かを実行することです。

代わりにシャットダウンフックを登録します...

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

于 2010-05-29T18:53:25.903 に答える
2

他の回答が言うように、finalizeを使用することは悪い習慣と見なされます。VMのシャットダウン時に何かが発生する「公式」の方法は、シャットダウンフックを使用することです。

シャットダウンフックは、作成するThreadオブジェクトですが、開始しないでください。これを Runtime.getRuntime()。addShutdownHook(Thread)に登録すると、VMのシャットダウン時に呼び出されます。

于 2010-05-29T18:43:27.557 に答える
2

効果的な Java 2nd Edition: 項目 7: ファイナライザーを避ける

ファイナライザは予測不可能で、危険な場合が多く、一般的に不要です。それらを使用すると、動作が不安定になり、パフォーマンスが低下し、移植性の問題が発生する可能性があります。ファイナライザーの有効な用途はほとんどありませんが [...]、経験則として、ファイナライザーは避けるべきです。

[...] ファイナライズを保証すると主張する唯一の方法はSystem.runFinalizersOnExit、 とその邪悪な双子ですRuntime.runFinalizersOnExit。これらのメソッドには致命的な欠陥があり、推奨されていません。

于 2010-05-29T18:38:16.030 に答える
1

Josh Bloch は、著書「Effective Java」の中で、ファイナライザーで何かを行うのは悪い習慣であると書いています。

オプションは、アプリケーションを閉じるたびに手動でこれを行うことです。

  • (で)閉じる場合はSystem.exit(0)、そのコードをそこに呼び出します
  • ユーザーがそれを閉じた場合は、リスナーを追加してそこに呼び出します。
于 2010-05-29T18:37:00.610 に答える
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を使用することは一般的に良い習慣ではないため、避ける必要があります。

于 2010-05-29T18:46:38.260 に答える
0

独自のログフレームワークを作成する代わりに、既存の多くのJavaログフレームワークの1つを確認することをお勧めします。私はlog4jを使用していますが、オプションはたくさんあります。より安定したコード、より少ないデバッグ作業、そしておそらくより速いパフォーマンスが得られます。そして、彼らはトリッキーなファイナライザーの振る舞いを必要としません。

于 2010-05-29T18:49:12.647 に答える