爲何在Java中不使用finalize()方法

咱們都知道finalize()方法是回收分配給對象的內存以前調用垃圾收集器線程的基本語句。在這篇文章中,咱們將會深刻這個方法。java

這篇文章中的章節:安全

一、finalize()方法不能保證執行(這個將要用例子來講明)ide

二、其餘不使用它的緣由性能

三、finalize()方法在性能上增長負擔spa

四、正確使用的指導.net

finalize()方法不能保證執行(這個將要用例子來講明)

讓咱們使用一個程序證實它,我已經寫了一個簡單的Java runnable例子,在try-catch-finally-finalize塊中每一個裏邊都有輸出語句。我已經建立了另外一個類,並建立runnable的三個實例,而後咱們看一下執行的過程。
[java]  view plain  copy
 
  1. public class TryCatchFinallyTest implements Runnable {  
  2.    
  3.     private void testMethod() throws InterruptedException  
  4.     {  
  5.         try  
  6.         {  
  7.             System.out.println("In try block");  
  8.             throw new NullPointerException();  
  9.         }  
  10.         catch(NullPointerException npe)  
  11.         {  
  12.             System.out.println("In catch block");  
  13.         }  
  14.         finally  
  15.         {  
  16.             System.out.println("In finally block");  
  17.         }  
  18.     }  
  19.    
  20.     @Override  
  21.     protected void finalize() throws Throwable {  
  22.         System.out.println("In finalize block");  
  23.         super.finalize();  
  24.     }  
  25.    
  26.     @Override  
  27.     public void run() {  
  28.         try {  
  29.             testMethod();  
  30.         } catch (InterruptedException e) {  
  31.             e.printStackTrace();  
  32.         }  
  33.     }  
  34. }  
 
[java]  view plain  copy
 
  1. public class TestMain  
  2. {  
  3.     @SuppressWarnings("deprecation")  
  4.     public static void main(String[] args) {  
  5.     for(int i=1;i<=3;i++)  
  6.     {  
  7.         new Thread(new TryCatchFinallyTest()).start();  
  8.     }  
  9.     }  
  10. }  
  11.    
  12. Output:  
  13.    
  14. In try block  
  15. In catch block  
  16. In finally block  
  17. In try block  
  18. In catch block  
  19. In finally block  
  20. In try block  
  21. In catch block  
  22. In finally block  

很神奇,線程中的finalize方法一點也沒有執行,這已經證實了我剛剛說明的事情。我想發生這件事的緣由是:finalizer是由垃圾收集器中的獨立線程控制執行的,若是Java虛擬機存在過久,垃圾回收器沒有時間建立和執行finalizers,若是錯了,請說明。
下一個問題是,咱們可以強制它執行嗎
答案是:是的,能夠,使用Runtime.runFinalizersOnExit(true);方法
[java]  view plain  copy
 
  1. public class TestMain  
  2. {  
  3.     @SuppressWarnings("deprecation")  
  4.     public static void main(String[] args) {  
  5.         for(int i=1;i<=3;i++)  
  6.         {  
  7.             new Thread(new TryCatchFinallyTest()).start();  
  8.             Runtime.runFinalizersOnExit(true);  
  9.         }  
  10.     }  
  11. }  
  12.    
  13. Output:  
  14.    
  15. In try block  
  16. In catch block  
  17. In finally block  
  18. In try block  
  19. In try block  
  20. In catch block  
  21. In finally block  
  22. In catch block  
  23. In finally block  
  24. In finalize block  
  25. In finalize block  
  26. In finalize block  

還有另外一個方法,Runtime.getRuntime().runFinalization(); 可是這隻能保證GC作出最大的努力,即便在咱們的程序中,咱們也不能保證3個線程中的finalize方法都能執行。
前一步,咱們使用Runtime.runFinalizersOnExit(true); 方法,這是另外一個遺憾,這個方法已經被JDK棄用,緣由是:這種方法本質上是不安全的,可能致使finalizers方法被活對象調用而其餘線程正在並行操做這個對象,從而致使不正確的行爲或者死鎖。因此,咱們不能以一種方式執行它而以另外一種方式置系統於危險中,最好咱們不使用它。

其餘不使用它的緣由

(1)finalize()方法不像構造方法在鏈中工做,意味着像當你調用構造方法的時候,超類中的構造方法也會被隱含的調用,可是在finalize()方法的這種狀況中,這種隱含的調用不會發生。超類中的finalize()方法須要顯示的調用。
假設,你建立了一個類而且當心翼翼的寫了finalize()方法。一些人來extend了你的類,可是在子類中的finalize()塊中沒有調用super.finalize()方法。而後超類中finalize()方法將永遠都不會被調用。
(2)任何有finalize()方法拋出的異常都會被GC線程忽略並且不會被進一步傳播,事實上也不會在日誌文件上記錄下來。

finalize()方法在性能上增長負擔

在第二版的effective Java中,做者說:「這有另一件事,使用finalize()方法還有另外的嚴重的性能問題,在個人機器上,建立和銷燬一個簡單的對象的時間大概是5.6ns,增長finalize()方法這個時間增長到2400ns,換句話說,使用finalize()方法建立和銷燬對象比不使用慢了430倍」。我也在個人系統上分析上述問題,可是沒有這麼大的差異,可是也是有一些差異的。可是在時間要求高的系統內,這也是一個很大的區別。
 

正確使用的指導

通過上邊的討論之路,若是你依舊發如今一些場景下使用finalize()方法是別要的,那麼請檢查下邊的觀點
(1)要在finalize()方法中一直調用super.finalize()
(2)考慮到不可預測預測性,不要在時間要求高的應用中使用finalize()
(3)不要使用Runtime.runFinalizersOnExit(true);方法,由於你可能將你的系統置於危險之中
(4)嘗試遵循下邊的模板使用finalize()方法
[java]  view plain  copy
 
  1. @Override  
  2. protected void finalize() throws Throwable  
  3. {  
  4.     try{  
  5.         //release resources here  
  6.     }catch(Throwable t){  
  7.         throw t;  
  8.     }finally{  
  9.         super.finalize();  
  10.     }  
  11. }  
原文連接:http://howtodoinjava.com/2012/10/31/why-not-to-use-finalize-method-in-java/
相關文章
相關標籤/搜索