为什么Java ThreadPoolExecutor覆盖finalize()
作者:互联网
我想知道为什么在终止所有线程之后,仅当GC调用finalize方法时,ThreadPoolExecutor finalize()方法才会调用其shutdown()方法的原因.那么,为什么ThreadPoolExecutor会完全覆盖finalize()?
ThreadPoolExecutor.finalize()调用shutdown()对我(以及我的项目的线程泄漏源)似乎具有误导性,因为这给人以强烈(但错误的)印象,即
-ThreadPoolExecutor管理其线程的生命周期,并在GC收集ThreadPoolExecutor对象时停止线程
-仅在需要确定性结果而不是依靠GC进行整理的情况下才需要调用shutdown()或shutdownNow()(显然,这样做的错误做法!)
笔记
在该线程中,why-doesnt-this-thread-pool-get-garbage-collected Affe解释了为什么客户端仍然需要调用shutdown()
在这个主题中,始发者why-threadpoolexecutor-finalize-invokes-shutdown-and-not-shutdownnow对此主题感到困惑,但答案却不如1中的全面.
ThreadPoolEecutor.finalize()的JavaDocs确实包含单词“并且它没有线程”,但这很容易被忽略.
解决方法:
首先,如果您认为这是一个错误,则将其报告给Oracle.
其次,我们不能肯定地回答您的问题,因为您本质上是在问“他们为什么设计这种方式”……而当他们做出决定时,我们不在那儿.
但是我怀疑原因是当前的选择被认为是两个弊端中的较小者:
>一方面,如果仅由于不再直接引用线程池而可以将其关闭,那么正在执行实际工作的线程可能会提前终止.
>另一方面,正如您所观察到的那样,线程池在直接访问更长的时间后不会自动关闭,可能是内存泄漏.
鉴于显然有避免存储泄漏的方法,我认为第二种选择(即当前的行为)弊端较小.
无论如何,有明确的证据表明设计者已经考虑了这种行为.即ThreadPoolExecutor javadoc中的以下引用:
Finalization
A pool that is no longer referenced in a program AND has no remaining threads will be shutdown automatically. If you would like to ensure that unreferenced pools are reclaimed even if users forget to call
shutdown()
, then you must arrange that unused threads eventually die, by setting appropriate keep-alive times, using a lower bound of zero core threads and/or settingallowCoreThreadTimeOut(boolean)
.
(以及那种答案的@fge注释.当非活动工作线程配置为超时时,就会发生这种情况.)
我也认为还有基于实现的原因.看一下代码here.
线程池中的每个线程都有对Runnable的引用,该引用实际上是内部类ThreadPoolExecutor.Worker的实例.这意味着从(活动的,虽然可能是空闲的)线程到ThreadPoolExecutor.Worker对象,再从该对象到封闭的ThreadPoolExecutor实例,都有一个强大的引用路径.并且由于活动线程始终是可访问的,因此ThreadPoolExecutor实例在所有线程真正终止之前仍可访问.
现在,我/我们无法告诉您行为或javadoc规范是第一个出现的.参见上方的“第二…”点…
但是,就像我上面说的(“首先…”)一样,如果您认为这是一个错误,请向Oracle报告.如果您认为javadoc具有误导性,也是如此……尽管我认为您的论点在我引用的材料中仍然很弱.
关于为什么在这种情况下,如果shutdown()什么也不做,他们为什么要重载finalize()来调用shutdown():
>在较早的版本中,它可能做了重要的事情,并且
> shutdown()方法以调用挂钩方法结束,该挂钩方法显然在子类中被重写以执行重要的工作……根据注释.
标签:threadpoolexecutor,multithreading,java,garbage-collection 来源: https://codeday.me/bug/20191121/2055797.html