我们都知道finalize()方法是回收分配给对象的内存之前调用垃圾收集器线程的基本语句。在这篇文章中,我们将会深入这个方法。

这篇文章中的章节:

1、finalize()方法不能保证执行(这个将要用例子来说明)

2、其他不使用它的原因

3、finalize()方法在性能上增加负担

4、正确使用的指导

finalize()方法不能保证执行(这个将要用例子来说明)

让我们使用一个程序证明它,我已经写了一个简单的Java runnable例子,在try-catch-finally-finalize块中每个里边都有输出语句。我已经创建了另一个类,并创建runnable的三个实例,然后我们看一下执行的过程。
  1. public class TryCatchFinallyTest implements Runnable {
  2. private void testMethod() throws InterruptedException
  3. {
  4. try
  5. {
  6. System.out.println("In try block");
  7. throw new NullPointerException();
  8. }
  9. catch(NullPointerException npe)
  10. {
  11. System.out.println("In catch block");
  12. }
  13. finally
  14. {
  15. System.out.println("In finally block");
  16. }
  17. }
  18. @Override
  19. protected void finalize() throws Throwable {
  20. System.out.println("In finalize block");
  21. super.finalize();
  22. }
  23. @Override
  24. public void run() {
  25. try {
  26. testMethod();
  27. } catch (InterruptedException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. }
 
  1. public class TestMain
  2. {
  3. @SuppressWarnings("deprecation")
  4. public static void main(String[] args) {
  5. for(int i=1;i<=3;i++)
  6. {
  7. new Thread(new TryCatchFinallyTest()).start();
  8. }
  9. }
  10. }
  11. Output:
  12. In try block
  13. In catch block
  14. In finally block
  15. In try block
  16. In catch block
  17. In finally block
  18. In try block
  19. In catch block
  20. In finally block

很神奇,线程中的finalize方法一点也没有执行,这已经证明了我刚刚说明的事情。我想发生这件事的原因是:finalizer是由垃圾收集器中的独立线程控制执行的,如果Java虚拟机存在太久,垃圾回收器没有时间创建和执行finalizers,如果错了,请说明。

下一个问题是,我们能够强制它执行吗
答案是:是的,可以,使用Runtime.runFinalizersOnExit(true);方法
  1. public class TestMain
  2. {
  3. @SuppressWarnings("deprecation")
  4. public static void main(String[] args) {
  5. for(int i=1;i<=3;i++)
  6. {
  7. new Thread(new TryCatchFinallyTest()).start();
  8. Runtime.runFinalizersOnExit(true);
  9. }
  10. }
  11. }
  12. Output:
  13. In try block
  14. In catch block
  15. In finally block
  16. In try block
  17. In try block
  18. In catch block
  19. In finally block
  20. In catch block
  21. In finally block
  22. In finalize block
  23. In finalize block
  24. In finalize block

还有另一个方法,Runtime.getRuntime().runFinalization(); 但是这只能保证GC做出最大的努力,即使在我们的程序中,我们也不能保证3个线程中的finalize方法都能执行。

前一步,我们使用Runtime.runFinalizersOnExit(true); 方法,这是另一个遗憾,这个方法已经被JDK弃用,原因是:这种方法本质上是不安全的,可能导致finalizers方法被活对象调用而其他线程正在并行操作这个对象,从而导致不正确的行为或者死锁。所以,我们不能以一种方式执行它而以另一种方式置系统于危险中,最好我们不使用它。

其他不使用它的原因

(1)finalize()方法不像构造方法在链中工作,意味着像当你调用构造方法的时候,超类中的构造方法也会被隐含的调用,但是在finalize()方法的这种情况中,这种隐含的调用不会发生。超类中的finalize()方法需要显示的调用。
假设,你创建了一个类并且小心翼翼的写了finalize()方法。一些人来extend了你的类,但是在子类中的finalize()块中没有调用super.finalize()方法。然后超类中finalize()方法将永远都不会被调用。
(2)任何有finalize()方法抛出的异常都会被GC线程忽略而且不会被进一步传播,事实上也不会在日志文件上记录下来。

finalize()方法在性能上增加负担

在第二版的effective Java中,作者说:“这有另外一件事,使用finalize()方法还有另外的严重的性能问题,在我的机器上,创建和销毁一个简单的对象的时间大概是5.6ns,增加finalize()方法这个时间增加到2400ns,换句话说,使用finalize()方法创建和销毁对象比不使用慢了430倍”。我也在我的系统上分析上述问题,但是没有这么大的差别,但是也是有一些差别的。但是在时间要求高的系统内,这也是一个很大的区别。
 

正确使用的指导

经过上边的讨论之路,如果你依旧发现在一些场景下使用finalize()方法是别要的,那么请检查下边的观点
(1)要在finalize()方法中一直调用super.finalize()
(2)考虑到不可预测预测性,不要在时间要求高的应用中使用finalize()
(3)不要使用Runtime.runFinalizersOnExit(true);方法,因为你可能将你的系统置于危险之中
(4)尝试遵循下边的模板使用finalize()方法
  1. @Override
  2. protected void finalize() throws Throwable
  3. {
  4. try{
  5. //release resources here
  6. }catch(Throwable t){
  7. throw t;
  8. }finally{
  9. super.finalize();
  10. }
  11. }
原文链接:http://howtodoinjava.com/2012/10/31/why-not-to-use-finalize-method-in-java/

为什么在Java中不使用finalize()方法的更多相关文章

  1. JAVA中GC时finalize()方法是不是一定会被执行?

    在回答上面问题之前,我们一定要了解JVM在进行垃圾回收时的机制,首先: 一.可达性算法  要知道对象什么时候死亡,我们需要先知道JVM的GC是如何判断对象是可以回收的.JAVA是通过可达性算法来来判断 ...

  2. finalize() 方法——Java中垃圾回收提醒方法

    finalize() Java 允许定义这样的方法,它在对象被垃圾收集器析构(回收)之前调用,这个方法叫做 finalize( ),它用来清除回收对象. 例如,你可以使用 finalize() 来确保 ...

  3. 【Java面试题系列】:Java中final finally finalize的区别

    本篇为[Java面试题系列]第三篇,文中如有错误,欢迎指正. 第一篇链接:[Java面试题系列]:Java基础知识常见面试题汇总 第一篇 第二篇链接:[Java面试题系列]:Java基础知识常见面试题 ...

  4. java中substring的使用方法

    java中substring的使用方法 str=str.substring(int beginIndex);截取掉str从首字母起长度为beginIndex的字符串,将剩余字符串赋值给str: str ...

  5. Java中Set的contains()方法

    Java中Set的contains()方法 -- hashCode与equals方法的约定及重写原则 翻译人员: 铁锚 翻译时间: 2013年11月5日 原文链接: Java hashCode() a ...

  6. [java,2017-05-16] java中清空StringBuffer的方法以及耗费时间比较

    java中清空StringBuffer的方法,我能想到的有4种: 1. buffer.setLength(0);  设置长度为0 2. buffer.delete(0, buffer.length() ...

  7. java中BorderLayout的使用方法

    相关设置: 使用BorderLayout布局上下左右中布局5个按键,单击中间的那个按键时就关闭窗口 代码: /**** *java中BorderLayout的使用方法 * 使用BorderLayout ...

  8. 【Java】Java中常用的String方法

    本文转载于:java中常用的String方法 1 length()字符串的长度 String a = "Hello Word!"; System.out.println(a.len ...

  9. Java中Set的contains()方法——hashCode与equals方法的约定及重写原则

    转自:http://blog.csdn.net/renfufei/article/details/14163329 翻译人员: 铁锚 翻译时间: 2013年11月5日 原文链接: Java hashC ...

随机推荐

  1. iOS-获取苹果商店iPhone应用程序编号APPID-应用中跳转到AppStore中的其他应用

    iOS-获取苹果商店iPhone应用程序编号APPID-应用中跳转到AppStore中的其他应用 一 获取苹果商店iPhone应用程序编号APPID 1 在mac上打开itunes  选择中的A 然后 ...

  2. FreeRTOS——任务调度—抢占式,时间片和合作式

    以下转载自安富莱电子: http://forum.armfly.com/forum.php 本章教程为大家将介绍 FreeRTOS 操作系统支持的任务调度方式:抢占式,时间片和合作式,这部分算是 Fr ...

  3. cocos2dx场景切换的坑

    有一个类可以使用不同的数据源,每个数据源对应一个对象. 我在类里保存了对象的实例,由于要在其它地方使用所以做成了静态,并在每次初始化时 重新设置,析构时删除. 现在我打开了A,切换到B,结果这个静态的 ...

  4. 微信小程序 - IOS 仿饿了么"我的",下拉橡皮筋效果

    这个需求是在wepy交流群里有群友提到的. 一个小花样. 注册mixins /** * IOS专用 顶部下拉橡皮筋效果 * 安卓的Page在到达顶部的时候,不能继续下拉...略过 * * 效果见 饿了 ...

  5. MySQL5.0、5.1、5.5、5.6功能进化

    目前线上使用的版本情况:新上线端口统一使用5.5,不说别的,一个快速恢复重启就值回票价. 但因为历史原因还有大量5.1的版本,甚至,I’am sorry,还有少数5.0的版本. 至于5.0以前的版本, ...

  6. 【转】VC调试的时候 “没有调试信息,未加载符号”

    概述调试是一个程序员最基本的技能,其重要性甚至超过学习一门语言.不会调试的程序员就意味着他即使会一门语言,却不能编制出任何好的软件.这里我简要的根据自己的经验列出调试中比较常用的技巧,希望对大家有用. ...

  7. Linux - 用户管理常用命令

    1.查看Linux已经存在的用户: [root@CMCC_91 ~]# cut -d : -f 1 /etc/passwd [root@CMCC_91 ~]# cat /etc/passwd |awk ...

  8. ComBoFuzzySearch.js

    /** * combobox和combotree模糊查询 */(function () { //combobox可编辑,自定义模糊查询 $.fn.combobox.defaults.editable ...

  9. 使ie9以下版本支持canvas,css3等主流html5技术的方法

    1.前言.   ie6,7,8支持html5,看起来比较难,其实有一种方法很通用,就是引入js和css,这种可插拔的引入对开发很有帮助.比如,下面是一个让网页支持canvas和css3的例子. 2.例 ...

  10. Android之自己定义checkbox样式

    大部分情况下,我们在UI中并不採用android自带的checkbox复选框样式,这时候就须要我们自己定义自己的checkbox. 首先找两张checkbox背景图片.比方下图样子的: 然后在draw ...