避免使用終結方法(finalizer)終結方法(finalizer)通常是不可預測的,也是很危險的,一般情況下是不必要的。不要把finalizer當成C++中析構函數的對應物。java中,當對象不可達時(即沒有引用指向這個對象時),會由垃圾回收器來回收與該對象相關聯的記憶體資源;而其他的記憶體資源,則一...
避免使用終結方法(finalizer)
終結方法(finalizer)通常是不可預測的,也是很危險的,一般情況下是不必要的。
不要把finalizer當成C++中析構函數的對應物。java中,當對象不可達時(即沒有引用指向這個對象時),會由垃圾回收器來回收與該對象相關聯的記憶體資源;而其他的記憶體資源,則一般由try-finally代碼塊來完成類似的工作。
一、finalizer的缺點:
1. 終結方法的缺點在於不能保證會被及時地執行。
及時執行finalizer方法是JVM垃圾回收方法的一個主要功能。由於不同JVM的垃圾回收演算法不同,JVM會“非故意的”延遲執行終結方法,因此終結方法的執行時間點是非常不穩定的。
2.finalizer方法的線程優先順序比當前程式的其他線程優先順序要低,且JAVA語言規範不保證哪個線程可以執行finalizer方法。
3.JAVA語言規範不僅不保證及時執行finalizer方法,還不保證一定會執行finalizer方法。當程式終止時,有可能一些對象的finalizer方法還沒有執行。——不應該依賴finalizer方法來更新重要的持久狀態。
4.System.gc和System.runFinalization不保證finalizer一定執行。
5.System.runFinalizersOnExit Runtime.runFinalizersOnExit 可以保證finalizer一定執行,但是這兩個方法已經廢棄。
6.如果未捕獲的異常在finalizer方法中拋出來,這個異常可以被忽略(警告都不會列印出來),且finalizer方法會終止。這樣這個異常就使對象處於“被破壞”的狀態,如果另一個線程要使用這個對象,就可能發生不確定的行為。
7.finalizer方法會有非常嚴重的(Severe)性能損失
二、不用finalizer方法,怎麼來實現線程中對象資源的終止呢?
使用顯示終止方法。
顯示終止方法的要求:
1.實例必須記錄下自己是否已經被終止了
2.顯示終止方法必須在一個私有域中記錄下“該對象已經不再有效”
3.在執行終止方法之後,執行對象其他方法時要檢查“該對象已經不再有效”私有域,拋出IllegalStateException。
顯示終止方法的例子:
1.InputStream
2.OutputStream
3.java.sql.Connection
4.java.util.Timer
顯示終止方法的使用方法:通常和try-finally一起使用,以確保及時終止。
FileInputStream fileInputStream = new FileInputStream();
try{
//Do something about fileInputStream;
}finally{
fileInputStream.close();
}
三、終結方法的合法用途。
1.作為安全網——顯示終止方法忘記調用的時候
2.終止非關鍵的本地資源(android JNI操作中)
四、終結方法的執行過程中要保證:如果子類的終結過程出現異常,超類的終結過程也會得到執行。
由於終結方法鏈不會自動執行,因此我們需要手動保證這一點。
方法一:使用try – finalize 代碼結構
@Override
protected void finalize() throws Throwable {
try{
...//Finalize subclass state
} finally {
super.finalize();
}
}
方法二:使用finalizer guardian(終結方法守衛者)
class A {
//終結守衛者
private final Object finalizerGuardian = new Object() {
@Override
//終結守衛者的終結方法將被執行
protected void finalize() {
//finalizer這outer class ——A
System.out.println("A finalize by the finalizerGuardian");
}
};
總之,
1.除非是作為安全網或者是為了終結非關鍵的本地資源,否則請不要使用終結方法。
2.如果確實需要,可以使用顯示終止方法
2.如果沒辦法真的使用了finalize,別忘記了調用super.finalize()。還可以考慮是否使用終結方法守衛者,使未調用super.finalize()方法的類的父類的終結方法也會被執行。
參考資料:
《Effective Java 第二版》