本條目大意
盡量避免在類中使用終結(jié)(finalize)方法,在里面寫一些釋放類中資源的語句。
為什么要避免使用 finalize方法?
1、java語言規(guī)范不僅不保證 finalize方法會被及時地執(zhí)行,而且根本不保證他們會被執(zhí)行。 2、System.gc 和 System.runFinalization 這兩個方法只是增加了finalizer 方法被執(zhí)行的機會。 3、唯一能保證 finalize 方法被執(zhí)行的方法有兩個,System.runFinalizersOnExit 和 Runtime.runFinalizersOnExit ,但是這兩個方法已經(jīng)被廢棄。 4、覆蓋并使用終結(jié)方法會有嚴重的性能損失。 5、及時地執(zhí)行終結(jié)方法是垃圾回收算法的一個主要功能,但是在不同的JVM實現(xiàn)中會大相庭徑,使用終結(jié)方法可能會喪失平臺無關(guān)性。
如果類的對象中封裝的資源確實需要進行釋放,我們應(yīng)該怎么做呢?
一般來說,需要釋放資源的有線程或者文件還有涉及到本地資源的對象。
我們不去覆蓋 finalize 方法,而是自己提供一個顯式的終止資源的方法。比如 java.io.FileInputStream 的close 方法。當使用完這個FileInputStream對象時,顯式調(diào)用close() 來回收資源。
我們首先看看 FileInputStream 是怎么玩的:
public void close() throws IOException { synchronized (closeLock) { if (closed) { return; } closed = true; } if (channel != null) { fd.decrementAndGetUseCount(); channel.close(); } int useCount = fd.decrementAndGetUseCount(); if ((useCount <= 0) || !isRunningFinalize()) { close0(); }}要求此類的使用者不再使用此類的時候調(diào)用 close 終止方法,進行釋放資源,并且在類中添加一個 closed 來標記資源是否已經(jīng)釋放,如果已經(jīng)被釋放了,那此類中的方法如果再被調(diào)用的話就拋出異常。
抽象形式如下:
class MyObject{ PRivate boolean isClosed = false; //終止方法 public void close(){ //資源釋放操作... isClosed = true; }}public static void main(String... args) { MyObject object = new MyObject(); try{ //在這里使用調(diào)用方法... } finally { //在這里關(guān)閉 object.close(); }}終結(jié)方法的用途
再繼續(xù)往下看,就會看到 FileInputStream 還是有覆蓋 finalize方法的。
protected void finalize() throws IOException { if ((fd != null) && (fd != FileDescriptor.in)) { runningFinalize.set(Boolean.TRUE); try { close(); } finally { runningFinalize.set(Boolean.FALSE); } }}清楚的看到方法里面進行調(diào)用了 close 方法,這是為了當對象持有者忘記調(diào)用前面段落中建議的顯式終結(jié)方法 :close()的情況下,使用inalize 方法充當“安全網(wǎng)”這是終結(jié)方法是用途之一。
抽象形式如下:
class MyObject{ private boolean isClosed = false; //終止方法 public void close(){ //資源釋放操作... isClosed = true; } //安全網(wǎng) protected void finalize() throws Throwable { try{ close(); } finally { super.finalize(); } }}終結(jié)方法還有一個好處,把終結(jié)方法放在一個匿名的類,該匿名類的唯一用途就是終結(jié)它的外圍實例。 外圍實例持有對終結(jié)方法守衛(wèi)者的唯一實例,這意味著當外圍實例是不可達時,這個終結(jié)方法守衛(wèi)者也是不可達的了,垃圾回收器回收外圍實例的同時也會回收終結(jié)方法守衛(wèi)者的實例,而終結(jié)方法守衛(wèi)者的finalize方法就把外圍實例的資源釋放掉,就好像是終結(jié)方法是外圍實例的一個方法一樣。
看看 java.util.Timer 的終結(jié)方法守衛(wèi)者:
public void cancel() { synchronized(queue) { thread.newTasksMayBeScheduled = false; queue.clear(); queue.notify(); // In case queue was already empty. }}private final Object threadReaper = new Object() { protected void finalize() throws Throwable { synchronized(queue) { thread.newTasksMayBeScheduled = false; queue.notify(); // In case queue is empty. } }};cancel 方法是 Timer 提供的顯式終止方法,threadReaper 是一個私有變量,保證除了實例本身外沒有對它的引用,它覆蓋 finalize 方法,實現(xiàn)與 cancel 方法一樣的功能。
新聞熱點
疑難解答