咱們都知道finalize()方法是回收分配給對象的內存以前調用垃圾收集器線程的基本語句。在這篇文章中,咱們將會深刻這個方法。java
這篇文章中的章節:安全
一、finalize()方法不能保證執行(這個將要用例子來講明)ide
二、其餘不使用它的緣由性能
三、finalize()方法在性能上增長負擔spa
四、正確使用的指導.net
finalize()方法不能保證執行(這個將要用例子來講明)
讓咱們使用一個程序證實它,我已經寫了一個簡單的Java runnable例子,在try-catch-finally-finalize塊中每一個裏邊都有輸出語句。我已經建立了另外一個類,並建立runnable的三個實例,而後咱們看一下執行的過程。
- public class TryCatchFinallyTest implements Runnable {
-
- private void testMethod() throws InterruptedException
- {
- try
- {
- System.out.println("In try block");
- throw new NullPointerException();
- }
- catch(NullPointerException npe)
- {
- System.out.println("In catch block");
- }
- finally
- {
- System.out.println("In finally block");
- }
- }
-
- @Override
- protected void finalize() throws Throwable {
- System.out.println("In finalize block");
- super.finalize();
- }
-
- @Override
- public void run() {
- try {
- testMethod();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- public class TestMain
- {
- @SuppressWarnings("deprecation")
- public static void main(String[] args) {
- for(int i=1;i<=3;i++)
- {
- new Thread(new TryCatchFinallyTest()).start();
- }
- }
- }
-
- Output:
-
- In try block
- In catch block
- In finally block
- In try block
- In catch block
- In finally block
- In try block
- In catch block
- In finally block
很神奇,線程中的finalize方法一點也沒有執行,這已經證實了我剛剛說明的事情。我想發生這件事的緣由是:finalizer是由垃圾收集器中的獨立線程控制執行的,若是Java虛擬機存在過久,垃圾回收器沒有時間建立和執行finalizers,若是錯了,請說明。
下一個問題是,咱們可以強制它執行嗎
答案是:是的,能夠,使用Runtime.runFinalizersOnExit(true);方法
- public class TestMain
- {
- @SuppressWarnings("deprecation")
- public static void main(String[] args) {
- for(int i=1;i<=3;i++)
- {
- new Thread(new TryCatchFinallyTest()).start();
- Runtime.runFinalizersOnExit(true);
- }
- }
- }
-
- Output:
-
- In try block
- In catch block
- In finally block
- In try block
- In try block
- In catch block
- In finally block
- In catch block
- In finally block
- In finalize block
- In finalize block
- 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()方法
- @Override
- protected void finalize() throws Throwable
- {
- try{
-
- }catch(Throwable t){
- throw t;
- }finally{
- super.finalize();
- }
- }
原文連接:http://howtodoinjava.com/2012/10/31/why-not-to-use-finalize-method-in-java/