我们都知道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. 工作流Activiti的学习总结(十二) activiti官方十分钟快速学习 (zhuan)

    http://topmanopensource.iteye.com/blog/1315341 ***************************************************** ...

  2. 第八课:不一样的链表 linux链表设计哲学 5星级教程

    这一课最后实现的链表,和普通链表不同,借鉴了linux内核链表的思想,这也是企业使用的链表. 基础介绍: 顺序表的思考 顺序表的最大问题是插入和删除需要移动大量的元素!如何解决?A:在线性表数据元素之 ...

  3. lucene 内存索引存储每个field里内容的相关代码

    相关的类调用关系 DocumentsWriterPerThread ——>DocFieldProcessor   DocumentsWriterPerThread里的consumer对象(类型是 ...

  4. UCOS2系统内核讲述_总体描述

    Ⅰ.写在前面 学习本文之前可以参考我前面基于STM32硬件平台移植UCOS2的几篇文章,我将其汇总在一起: UCOS2_STM32F1移植详细过程(汇总文章) 要想学习,或使用系统配套的资源(如:信号 ...

  5. netlink--内核态与用户态通信

    1. 什么是 Netlink 什么是Netlink?Netlink是linux提供的用于内核和用户态进程之间的通信方式.但是注意虽然Netlink主要用于用户空间和内核空间的通信,但是也能用于用户空间 ...

  6. Supervisor重新加载配置启动新的进程

    一.添加好配置文件后 二.更新新的配置到supervisord supervisorctl update 三.重新启动配置中的所有程序 supervisorctl reload 四.启动某个进程(pr ...

  7. Lua中的字符串函数库

    字符串库中的一些函数是非常简单的: string.len(s)          返回字符串s的长度:string.rep(s, n)      返回重复n次字符串s的串:你使用string.rep( ...

  8. 解决阿里云部署 office web apps ApplicationFailedException 报错问题

    查找这个问题,确实花费了很长时间,所以具体解析一下问题原因吧. 报错如下: 问题详情链接 New-OfficeWebAppsFarm:Office Online服务无法启动.有关详细信息,请参阅Win ...

  9. 新型智能芯片nxp----嗯质朴

    公司omap 用到nxp的qx 操作系统   由飞利浦公司创立,已拥有五十年的悠久历史,主要提供工程师与设计人员各种半导体产品与软件,为移动通信.消费类电子.安全应用.非接触式付费与连线,以及车内娱乐 ...

  10. Excel 经常使用的公式总结

    INDIRECT 返回并显示指定引用的内容.使用INDIRECT函数可引用其他工作簿的名称.工作表名称和单元格引用.   indirect函数对单元格引用的两种 A B C D INDIRECT(&q ...