程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA編程入門知識 >> Java 理論與實踐:良好的內務處理實踐

Java 理論與實踐:良好的內務處理實踐

編輯:JAVA編程入門知識

  垃圾收集幾乎是每個開發人員都喜愛的一個 Java 平台特性,它簡化了開發,消除了所有種類的潛在代碼錯誤。可盡管垃圾收集一般來說可以讓您無需進行資源治理,有時候您還是必須自己進行一些內務處理。在本文中,Brian Goetz 討論了垃圾收集的局限性,並指出了您必須自己做內務處理的場景。
  
  小時候,父母總是叮囑我們玩了玩具之後要收好。假如您仔細想想,其實這種唠叨並不過分,要保持整潔是因為存在實際的限制,房間裡沒有太多的空間,假如到處堆滿了玩具,那麼連走路都無處下腳了。
  
  假如有了足夠的空間,保持整潔就不是那麼必要了。空間越多,就越不必要保持整潔。Arlo Guthrie 聞名的民謠 Alice's Restaurant Massacre 說明了這一點:
  
  他們住在教堂樓下的大廳,裡面的椅子全都搬走了,剩下一個空蕩蕩的大房間,所以他們想,很長時間都不用把垃圾扔出去,有的是地方裝垃圾……
  
  無論如何,垃圾收集可以幫我們減輕內務整理方面的工作。
  
  顯式地釋放資源
  
  Java 程序中使用的絕大多數資源都是對象,垃圾收集在清理對象方面做得很好。因此,您可以使用任意多的 String。垃圾收集器最終無需您的干預就會算出它們何時失效,並收回它們使用的內存。
  
  另一方面,像文件句柄和套接字句柄這類非內存資源必須由程序顯式地釋放,比如使用 close()、destroy()、shutdown() 或 release() 這樣的方法來釋放。有些類,比如平台類庫中的文件句柄流實現,提供終結器(finalizer)作為安全保證,以便當垃圾收集器確定程序不再使用資源而程序卻忘了釋放資源時,終結器還可以來做這個釋放工作。但是盡管文件句柄提供了終結器來在您忘記了時為您釋放資源,最好還是在使用完之後顯式地釋放資源。這樣做可以更早地釋放資源,降低了資源耗盡的可能。
  
  對於有些資源來說,一直等到終結(finalization)釋放它們是不可取的。對於重要的資源,比如鎖獲取和信號量許可證,Lock 或 Semaphore 直到很晚都可能不會被垃圾收集掉。對於數據庫連接這樣的資源,假如您等待終結,那麼肯定會消耗完資源。許多數據庫服務器根據許可的容量,只接受一定數量的連接。假如服務器應用程序為每個請求都打開一個新的數據庫連接,然後用完之後就不管了,那麼數據庫遠遠未到終結器關閉不再需要的連接,就會到達它的最高容量。
  
  只限於一個方法的資源
  
  多數資源都不會持續整個應用程序的生命周期,相反,它們只被用於一個活動的生命周期。當應用程序打開一個文件句柄讀取文件以處理文檔時,它通常讀取文件後就不再需要文件句柄了。
  
  在最簡單的情況下,資源在同一個方法調用中被獲取、使用和釋放,比如清單 1 中的 loadPropertiesBadly() 方法:
  
  清單 1. 不正確地在一個方法中獲取、使用和釋放資源 —— 不要這樣做
  
   public static Properties loadPropertiesBadly(String fileName)
  throws IOException {
   FileInputStream stream = new FileInputStream(fileName);
   Properties props = new Properties();
   props.load(stream);
   stream.close();
   return props;
  }
  不幸的是,這個例子存在潛在的資源洩漏。假如一切進展順利,流將會在方法返回之前被關閉。但是假如 props.load() 方法拋出一個 IOException,那麼流則不會被關閉(直到垃圾收集器運行其終結器)。解決方案是使用 try...finally 機制來確保流被關閉,而不管是否發生錯誤,如清單 2 所示:
  
  清單 2. 正確地在一個方法中獲取、使用和釋放資源
  
   public static Properties loadProperties(String fileName)
  throws IOException {
   FileInputStream stream = new FileInputStream(fileName);
   try {
  Properties props = new Properties();
  props.load(stream);
  return props;
   }
   finally {
  stream.close();
   }
  }
  注重,資源獲取(打開文件)是在 try 塊外面進行的;假如把它放在 try 塊中,那麼即使資源獲取拋出異常,finally 塊也會運行。不僅該方法會不適當(您無法釋放您沒有獲取的資源),finally 塊中的代碼也可能拋出其自己的異常,比如 NullPointerException。從 finally 塊拋出的異常取代導致塊退出的異常,這意味著原來的異常丟失了,不能用於幫助進行調試。 並不總像看起來那麼輕易
  
  使用 finally 來釋放在方法中獲取的資源是可靠的,但是當涉及多個資源時,很輕易變得難以處理。下面考慮這樣一個方法,它使用一個 JDBC Connection 來執行查詢和迭代 ResultSet。該方法獲得一個 Connection,使用它來創建一個 Statement,並執行 Statement 以得到一個 ResultSet。但是中間 JDBC 對象 Statement 和 ResultSet 具有它們自己的 close() 方法,並且當您使用完之後,應該釋放這些中間對象。然而,進行資源釋放的 “明顯的” 方式並不起作用,如清單 3 所示:
  
  清單 3. 不成功的釋放多個資源的企圖 —— 不要這樣做
  
  
 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved