之前在牛客上看到一道面试题,是关于“finally子句是否总是一定会被执行”。在初学Java异常章节的时候,学习到try-catch-finally
的语句,说明了finally
子句的用途是用于确保安全的回收资源等,因此finally
子句总是会被系统执行。而学习到并发章节的时候,找到了一个特例。章节内容见《Java编程思想》第21章-21.2.8-后台线程
。
如下一段代码:
1 | class ADaemon implements Runnable { |
由于线程t
被注册为后台线程,因此当执行该程序后,finally
子句将不会得到执行,除非注释掉setDaemon()
的调用。结合书中所述,由于非后台线程main()
被终止时,后台线程会“突然”终止,即JVM会在main()
退出后立即关闭所有后台进程,而不会有任何被希望出现的确认形式。故在这种情况下,finally
子句将无法被执行。
2020.8.23更新,摘自《Java并发编程的艺术》
当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会退出。因此在构建Daemon线程时,不能依靠finally块中的内容来确保执行关闭或清理资源的逻辑。
在牛客的面试题中,一条回答表示“当在finally子句前调用System.exit(0)”时,finally
子句就不会被执行。即如上后台线程示例的情况一致,由于在main()
线程中退出,其退出动作发生在run()
中的finally
子句之前,故finally
子句将不会被执行。
关于这个问题涉及到JVM的运行机制以及线程等问题,在此先留题占坑,等待后续学习到更加清晰的原因时再来补充解释。(2020.5.25)