Java 為什么要避免使用finalizer和Cleaner
java9之前finalizer,java9使用cleaner代替了finalizer。相比f(wàn)inalizer,cleaner(它存在于一個(gè)獨(dú)立類Cleaner中,需要時(shí)候注入到對(duì)應(yīng)類中即可)不會(huì)污染API而且cleaner有類庫(kù)可以控制它的線程(它兩都在后臺(tái)線程中執(zhí)行)。
避免使用的原因:行為的不穩(wěn)定性它兩都不能保證及時(shí)的執(zhí)行,從方法可達(dá)到(對(duì)象被置空了)開始到最終的執(zhí)行,時(shí)間是任意長(zhǎng)的。所以千萬(wàn)不要使用他們來(lái)更新重要的持久狀態(tài),如釋放流資源、分布式鎖等。
System.gc和System.runFinalization這兩個(gè)方法會(huì)增加finalizer和cleaner被執(zhí)行的機(jī)會(huì),但是不保證一定會(huì)執(zhí)行。唯一能保證它兩會(huì)被執(zhí)行的兩個(gè)方法(System.runFinalizersOnExit和Runtime.runFinalizersOnExit)有致命的缺陷,已經(jīng)被廢除很久了。
移植性問(wèn)題不同的JVM堆垃圾回收的算法不同,如果程序依賴finalizer或者cleaner被執(zhí)行的時(shí)間點(diǎn),那么程序的表現(xiàn)可能截然不同
性能問(wèn)題finalizer和cleaner有一個(gè)非常嚴(yán)重的性能損耗。
安全問(wèn)題 finalizer中如果出現(xiàn)異常會(huì)導(dǎo)致線程終止,但是不會(huì)打印線程軌跡甚至警告都不會(huì)打印出來(lái),而且使正在銷毀的對(duì)象處于破壞狀態(tài),另一個(gè)線程如果使用這個(gè)破壞狀態(tài)的對(duì)象會(huì)出現(xiàn)行為的不確定性。cleaner沒(méi)有這個(gè)問(wèn)題。 finalizer攻擊:利于finalizer方法,構(gòu)建出惡意子類對(duì)象,非法調(diào)用父類方法。final類不會(huì)被構(gòu)建惡意子類,所以不會(huì)遭到finalizer攻擊。對(duì)于非final類,重寫一個(gè)空的finalizer方法并用final修飾來(lái)防止finalizer攻擊。//構(gòu)建對(duì)象使用后不能再次被實(shí)例化public class Demo{ private boolean flag = true; //防止實(shí)例化 public Demo() { if (flag){ throw new RuntimeException('不準(zhǔn)許再次創(chuàng)建對(duì)象'); } } public void say() { System.out.println('DemoUtils.say'); }}//構(gòu)建非法子類class Demo2 extends Demo{ public Demo2(){} //構(gòu)建finalizer攻擊 @Override protected void finalize() throws Throwable { //會(huì)調(diào)用父類方法 this.say(); System.exit(0); } public static void main(String[] args) throws InterruptedException { try { //創(chuàng)建子類對(duì)象必然會(huì)調(diào)用父類構(gòu)造,所以會(huì)發(fā)生異常 //但是在gc中還是執(zhí)行了父類的方法 Demo demo = new Demo2(); demo.say(); } catch (Exception e) { System.out.println(e); } System.gc(); //給垃圾回收提供時(shí)間 Thread.sleep(5000); }}//運(yùn)行結(jié)果java.lang.RuntimeException: 不準(zhǔn)許再次創(chuàng)建對(duì)象DemoUtils.say兩個(gè)用處:安全網(wǎng)
當(dāng)資源的所有者忘記使用close方法的時(shí)候,finalizer和cleaner可以充當(dāng)安全網(wǎng),雖然不能保證及時(shí)的釋放資源,但是遲一點(diǎn)釋放總比永遠(yuǎn)不釋放要好。要使用這樣的安全網(wǎng)就要認(rèn)證的考慮清除是否值得付出這樣的代價(jià)。所以Java一些AutoCloseable實(shí)現(xiàn)中都添加了安全網(wǎng)。
這是FileOutputStream的源碼
本地對(duì)等體:java操作native方法其實(shí)是委托給一個(gè)本地對(duì)等體對(duì)象,使用完成后java對(duì)象會(huì)被GC回收,但是這個(gè)對(duì)等體對(duì)象不是java對(duì)象不會(huì)被會(huì)GC回收。如果這個(gè)對(duì)象性能可以接受,而且沒(méi)有需要及時(shí)釋放的資源那么就可以使用finalizer或者cleaner進(jìn)行回收了。但是如果這個(gè)對(duì)等體性能無(wú)法接受且擁有必須被及時(shí)終止的資源,那么就需要提供一個(gè)close方法了。
以上就是Java 為什么要避免使用finalizer和Cleaner的詳細(xì)內(nèi)容,更多關(guān)于Java 避免使用finalizer和Cleaner的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. IntelliJ IDEA導(dǎo)入jar包的方法2. SSM框架JSP使用Layui實(shí)現(xiàn)layer彈出層效果3. 刪除docker里建立容器的操作方法4. IntelliJ IDEA導(dǎo)出項(xiàng)目的方法5. .Net中的Http請(qǐng)求調(diào)用詳解(Post與Get)6. 如果你恨一個(gè)程序員,忽悠他去做iOS開發(fā)7. JS如何在數(shù)組指定位置插入元素8. IDEA調(diào)試源碼小技巧之辨別抽象類或接口多種實(shí)現(xiàn)類的正確路徑9. java使用xfire搭建webservice服務(wù)的過(guò)程詳解10. Java源碼解析之ClassLoader
