終結(jié)方法的缺點(diǎn)
終結(jié)方法(finalizer)是不可預(yù)測(cè)的虱岂,也是很危險(xiǎn)的竹捉。
使用終結(jié)方法會(huì)導(dǎo)致行為不穩(wěn)定、降低性能涧偷,以及可移植性問題簸喂。
使用終結(jié)方法會(huì)非常嚴(yán)重?fù)p失性能。
終結(jié)方法的缺點(diǎn)在于不能保證會(huì)被及時(shí)地執(zhí)行燎潮。從一個(gè)對(duì)象變得不可到達(dá)開始喻鳄,到它的終結(jié)方法被執(zhí)行,所花費(fèi)的這段時(shí)間是任意長(zhǎng)的确封。
注重時(shí)間的任務(wù)不應(yīng)該由終結(jié)方法來完成除呵。
及時(shí)地執(zhí)行終結(jié)方法正是GC算法的一個(gè)主要功能,這個(gè)算法在不同的JVM實(shí)現(xiàn)中會(huì)大相徑庭隅肥。
與C++的對(duì)比
不要把終結(jié)方法當(dāng)做是C++中析構(gòu)函數(shù)的對(duì)應(yīng)物竿奏。
在C++中袄简,析構(gòu)函數(shù)是回收一個(gè)對(duì)象所占用資源的常規(guī)方法腥放,是構(gòu)造函數(shù)所必須的對(duì)應(yīng)物。
在Java中绿语,當(dāng)一個(gè)對(duì)象變得不可到達(dá)的時(shí)候秃症,GC會(huì)回收與該對(duì)象相關(guān)聯(lián)的存儲(chǔ)空間,并不需要程序員做專門的工作吕粹。
C++的析構(gòu)函數(shù)也可以被用來回收其他的非內(nèi)存資源种柑。
在Java中,用try-finally塊來完成類似的工作匹耕。
終結(jié)方法的延遲執(zhí)行
延遲終結(jié)過程是一個(gè)現(xiàn)實(shí)問題聚请。例如,終結(jié)方法線程的優(yōu)先級(jí)比應(yīng)用程序中其他線程的都要低得多稳其。
Java語言規(guī)范并不保證那個(gè)線程將會(huì)執(zhí)行終結(jié)方法驶赏,所以,除了不使用終結(jié)方法之外既鞠,并沒有很輕便的方法能夠避免這樣的問題煤傍。
Java語言規(guī)范不僅不保證終結(jié)方法會(huì)被及時(shí)地執(zhí)行,而且根本就不保證它們會(huì)被執(zhí)行嘱蛋。當(dāng)一個(gè)程序終止的時(shí)候蚯姆,某些已經(jīng)無法訪問的的對(duì)象上的終結(jié)方法卻根本沒有被執(zhí)行五续,這是完全有可能的。
不應(yīng)該依賴終結(jié)方法來更新重要的持久狀態(tài)龄恋。
跟終結(jié)方法相關(guān)的四個(gè)方法
不要被System.gc()
和System.runFinalization()
這兩個(gè)方法所迷惑疙驾,它們確實(shí)增加了終結(jié)方法被執(zhí)行的機(jī)會(huì),但是它們并不保證終結(jié)方法一定會(huì)被執(zhí)行郭毕。
唯一聲稱保證終結(jié)方法會(huì)被執(zhí)行的方法是System.runFinalizersOnExit
荆萤,`Runtime.runFinalizersOnExit。這兩個(gè)方法都有指明的缺陷铣卡,已經(jīng)被廢棄了链韭。
終結(jié)方法不會(huì)處理異常
正常情況下,未被捕獲的異常將會(huì)被線程終止煮落,并打印出軌跡敞峭,但是,如果異常發(fā)生在終結(jié)方法之中蝉仇,則不會(huì)如此旋讹,甚至連警告都不會(huì)打印出來。
不要使用終結(jié)方法轿衔,而是提供顯示的終止方法
提供顯式的終止方法沉迹,并要求該類的客戶端在每個(gè)實(shí)例不再有用的時(shí)候調(diào)用這個(gè)方法。
該實(shí)例必須記錄下自己是否已經(jīng)被終止了:顯式的終止方法必須在一個(gè)私有域中記錄下“該對(duì)象已經(jīng)不再有效”害驹。
如果這些方法是在對(duì)象已經(jīng)終止之后被調(diào)用鞭呕,其他的方法就必須檢查這個(gè)域,并拋出IllegalStateException
異常宛官。
例如:
InputStrea
葫松、OutputStream
、java.sql.Connection
上的close
方法底洗,
java.uitl.Timer
上的cancel
方法腋么,它執(zhí)行必要的狀態(tài)改變,使得與Timer
實(shí)例相關(guān)聯(lián)的線程溫和地終止自己亥揖。
Image.flush
珊擂,它會(huì)釋放所有與Image
實(shí)例相關(guān)聯(lián)的資源,但是該實(shí)例仍然處于可用的狀態(tài)费变,如果有必要的話摧扇,會(huì)重新分配資源。
java.awt
中的Grahpics.dispose
和Window.dispose
胡控,這些方法的性能不好扳剿。
顯示的終止方法通常與try-finally結(jié)構(gòu)結(jié)合起來使用,以確保及時(shí)終止昼激。
終結(jié)方法的作用——終結(jié)方法充當(dāng)安全網(wǎng)
當(dāng)對(duì)象的所有者忘記調(diào)用顯示終止方法時(shí)庇绽,終結(jié)方法可以充當(dāng)安全網(wǎng)锡搜。遲一點(diǎn)釋放資源總比永遠(yuǎn)不釋放要好。
如果終結(jié)方法發(fā)現(xiàn)資源還未被終止瞧掺,則應(yīng)該在日志中記錄一條警告耕餐,因?yàn)檫@表示客戶端代碼中的一個(gè)Bug,應(yīng)該得到修復(fù)辟狈。
如果你正考慮編寫這樣的安全網(wǎng)終結(jié)方法肠缔,就要認(rèn)真考慮清楚,這種額外的保護(hù)是否值得你付出這份額外的代價(jià)哼转。
終結(jié)方法的作用——對(duì)象的本地對(duì)等實(shí)體
第二種合理用途與對(duì)象的本地對(duì)等體有關(guān)明未。
本地對(duì)等體是一個(gè)本地對(duì)象,普通對(duì)象通過本地方法委托給一個(gè)本地對(duì)象壹蔓。因?yàn)楸镜貙?duì)等體不是一個(gè)普通對(duì)象趟妥,所以GC不會(huì)知道它,當(dāng)它的Java對(duì)等體被回收的時(shí)候佣蓉,它不會(huì)被回收披摄。
在本地對(duì)等體并不擁有關(guān)鍵資源的前提下,終結(jié)方法正是執(zhí)行這項(xiàng)任務(wù)最合適的工具勇凭。
如果本地對(duì)等體擁有必須被及時(shí)終止的資源疚膊,那么該類就應(yīng)該具有一個(gè)顯式的終止方法。終止方法可以是本地方法虾标,或者它也可以調(diào)用本地方法寓盗。
子類不會(huì)自動(dòng)調(diào)用父類的終結(jié)方法
“終結(jié)方法鏈”并不會(huì)被自動(dòng)執(zhí)行。如果類有終結(jié)方法夺巩,并且子類覆蓋了終結(jié)方法贞让,子類的終結(jié)方法就必須手工調(diào)用超類的終結(jié)方法。應(yīng)該在一個(gè)try
塊中終結(jié)子類柳譬,并在相應(yīng)的finally
塊中調(diào)用超類的終結(jié)方法。這樣做可以保證:即使子類的終結(jié)過程拋出異常续镇,超類的終結(jié)方法也會(huì)得到執(zhí)行美澳。
防范子類不調(diào)用超類的終結(jié)方法:為每個(gè)將被終結(jié)的對(duì)象創(chuàng)建一個(gè)附加的對(duì)象。不是把終結(jié)方法放在要求終結(jié)處理的類中摸航,而是把終結(jié)方法放在一個(gè)匿名的類中制跟,該匿名類的唯一用途就是終結(jié)它的外圍實(shí)例。該匿名類的單個(gè)實(shí)例被稱為終結(jié)方法守衛(wèi)者酱虎,外圍類的每個(gè)實(shí)例都會(huì)創(chuàng)建這樣一個(gè)守衛(wèi)者雨膨。外圍實(shí)例在它的私有實(shí)例域中保存著一個(gè)對(duì)其終結(jié)方法守衛(wèi)者的唯一引用,因此終結(jié)方法守衛(wèi)者與外圍實(shí)例可以同時(shí)啟動(dòng)終結(jié)線程读串。當(dāng)守衛(wèi)者被終結(jié)的時(shí)候聊记,它執(zhí)行外圍類實(shí)例所希望的終結(jié)行為撒妈,就好像它的終結(jié)方法是外圍對(duì)象上的一個(gè)方法一樣:
對(duì)于每一個(gè)帶有終結(jié)方法的非final公有類,都應(yīng)該考慮使用這種方法排监。
總結(jié)
除非是作為安全網(wǎng)狰右,或者是為了終止非關(guān)鍵的本地資源,否則請(qǐng)不要使用終結(jié)方法舆床。
既然使用了終結(jié)方法棋蚌,就要記住調(diào)用super.finalize();
。
如果用終結(jié)方法作為安全網(wǎng)挨队,要記住記錄終結(jié)方法的非法用法谷暮。
如果需要把終結(jié)方法與公有的非final
類關(guān)聯(lián)使用,請(qǐng)考慮使用終結(jié)方法守衛(wèi)者盛垦,以確保即使子類的終結(jié)方法未能調(diào)用super.finalize();
坷备,該終結(jié)方法也會(huì)被執(zhí)行。