高效Java第七條避免使用終結(jié)方法

終結(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葫松、OutputStreamjava.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.disposeWindow.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í)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末情臭,一起剝皮案震驚了整個(gè)濱河市省撑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌俯在,老刑警劉巖竟秫,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異跷乐,居然都是意外死亡肥败,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門愕提,熙熙樓的掌柜王于貴愁眉苦臉地迎上來馒稍,“玉大人,你說我怎么就攤上這事浅侨∨耍” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵如输,是天一觀的道長(zhǎng)鼓黔。 經(jīng)常有香客問我,道長(zhǎng)不见,這世上最難降的妖魔是什么澳化? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮稳吮,結(jié)果婚禮上缎谷,老公的妹妹穿的比我還像新娘。我一直安慰自己灶似,他們只是感情好列林,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布瑞你。 她就那樣靜靜地躺著,像睡著了一般席纽。 火紅的嫁衣襯著肌膚如雪捏悬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天润梯,我揣著相機(jī)與錄音过牙,去河邊找鬼。 笑死纺铭,一個(gè)胖子當(dāng)著我的面吹牛寇钉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舶赔,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼扫倡,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了竟纳?” 一聲冷哼從身側(cè)響起撵溃,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锥累,沒想到半個(gè)月后缘挑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡桶略,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年语淘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片际歼。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惶翻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鹅心,到底是詐尸還是另有隱情吕粗,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布巴帮,位于F島的核電站溯泣,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏榕茧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一客给、第九天 我趴在偏房一處隱蔽的房頂上張望用押。 院中可真熱鬧,春花似錦靶剑、人聲如沸蜻拨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缎讼。三九已至收夸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間血崭,已是汗流浹背卧惜。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留夹纫,地道東北人咽瓷。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像舰讹,于是被迫代替她去往敵國(guó)和親茅姜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法月匣,類相關(guān)的語法钻洒,內(nèi)部類的語法,繼承相關(guān)的語法锄开,異常的語法素标,線程的語...
    子非魚_t_閱讀 31,623評(píng)論 18 399
  • 一:java概述:1,JDK:Java Development Kit院刁,java的開發(fā)和運(yùn)行環(huán)境糯钙,java的開發(fā)工...
    ZaneInTheSun閱讀 2,649評(píng)論 0 11
  • 一、終結(jié)方法VS析構(gòu)器 熟悉C++的都知道退腥,析構(gòu)器是用來回收一個(gè)對(duì)象所占用資源的常規(guī)方法任岸,是構(gòu)造器所必需的對(duì)應(yīng)物。...
    真愛也枉然閱讀 482評(píng)論 0 0
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理狡刘,服務(wù)發(fā)現(xiàn)享潜,斷路器,智...
    卡卡羅2017閱讀 134,651評(píng)論 18 139
  • 一. finalize()基本概念 所謂的終結(jié)方法其實(shí)是指finalize()嗅蔬。終結(jié)方法finalizer通常是不...
    Ruheng閱讀 3,019評(píng)論 3 3