天天看點

EffectiveJava-7 J避免使用 finalizer方法避免使用 finalizer 方法

避免使用 finalizer 方法

  實際上在實際項目開發中,我基本沒有使用到過該方法,原文中介紹了該方法的缺陷,和介紹了顯示終結方法的執行個體,以及 該方法在實際開發中的正确用途,如果真的要使用該方法應該主要的事項

finalizer方法的缺陷

  finalizer 方法通常是不可預的,也是很危險的額,一般情況下是不必要的,Java 語言規範不僅不保證 finalizer

方法會被及時執行,而且根本就不保證它們會被執行,當一個程式終結的時候,某些已經無法通路的對象上的 finalizer() 根本沒有被執行,這是完全有可能的額。結論是:不應該依賴 finalizer()方法來更新重要的持久狀态。例如,依賴終結方法來釋放共享資源(比如上傳資料庫)

上的永久鎖,很容易讓整個分布式系統垮掉(沒接觸過,并不了解)

  不要被System.gc和System.runFinaliztion 這兩個方法所疑惑,它們确實增加了終結方法被執行的機會,但是它們并不保證終結方法一定會被執行。唯一聲稱保證找終結方法被執行的方法是 System.runFinlizersonExit ,以及它們臭名昭著孿生兄弟Runtime.runFinalizersOnExit, 但是這2個方法都有緻命的 缺陷,已經被廢棄,不建議使用了。

  未被捕獲的異常會使對象處于破壞的狀态( a corrupt case),如果另一個線程企圖使用這種被破壞的對象,則可能發生任何不确定的行為。正常情況下,未被捕獲的異常将會時線程終止,并答應出棧軌迹(Stack Trace),但是,如果異常發生在終結方法總,則不會如此,甚至連警告都不會打出來。

  終結方法還有嚴重的性能損失。

如何正确終止對象中封裝的資源

  顯示終止方法的典型例子是 InputStram… 和 java.sql.Connectoin 上的close方法,它執行必要的狀态改變,但狀态處于非法時,你繼續使用将會抛出異常。

  顯示的終結方法通常與 try-finally 結構結合起來使用,以確定及時終止。在finally子句内部調用顯示的終結方法,可以保證即使在使用對象的時候又異常抛出,該終止方法也會被執行。

Foo foo = new foo(...);
    try{
    //做一些會發生異常的事
    } finaly{
        fpp.terminate();
    }
           

finalizer的合法用途

  第一種用途是,當對象的所有者忘記調用了前面介紹的建議的顯示終結方法,finalzier可以充當對象的安全網,雖然,它無法保證終結方法會被及時的調用,但是在用戶端無法通過調用顯示的終結方法來正常結束的情況下,遲一點釋放關鍵資源總比永遠不釋放要好。但是如果終結方法的調用時,發現資源确實是還沒被釋放,你應該用 log 記錄起來,因為這意味着你用戶端的一個 bug 你應該及時的修複它。

  第二種用途是,與 native method 的使用有關,普通對象通過 native method 委托給一個本地對象,因為native peer 并不是一個普通的方法,是以垃圾回收并不會制動它,當它的Java對象呗回收是,它并不會被會回收。在naatvei peer 并不具備關鍵的資源的情況下, finalizer 是一個最合适的工具,在native peer擁有必須被及時終止的資源時,那麼該類就應該具有一個現實的終止方法。

總結

總之,除非是作為安全網,或者是為了終止非關鍵的本地資源,否則不建議使用終結方法。如果使用了終結方法,就要記住調用了 super.finalize。