【问题标题】:Using the finalize method as an alternative to Timer?使用 finalize 方法作为 Timer 的替代方法?
【发布时间】:2017-02-10 06:25:22
【问题描述】:

我正在编写一个 REST 客户端,它有一个具有固定过期时间的访问令牌。

如何确保在过期时间之前请求新令牌?我看到两个选项:

  1. Timer
  2. 一些使用finalize 方法的恶作剧可能使用ref package

1) 将要求我创建一个在给定时间内运行并请求新令牌的新线程。这对我来说似乎很浪费。

2) 将利用无论如何都会运行的 GC 线程,因此我不需要创建新线程。当finalize 运行时,只需检查令牌是否即将过期,如果是则请求一个新的,如果在下一个 GC 循环运行之前再次使对象可用。

评论或其他想法?

【问题讨论】:

  • GC thread which will run anyways。这可能并不总是正确的。 GC 仅在需要运行时才由 JVM 运行。如果您的应用程序有足够的可用内存,则可能根本不会触发 GC。所以,我建议不要依赖这种方法。
  • 每当我有两种选择,而另一种是“一些恶作剧”时,我总是会这样做。让代码更有趣⸮
  • 仍然过早的优化或者在这种情况下过早的聪明不是一个好主意。仅仅因为某件事似乎是浪费的,并不能很好地表明它是否是一个好主意。如果您正在创建 1 个计时器,您甚至不需要考虑它。如果您有 1000 个并且它们正在造成性能损害,那么您需要考虑替代方案。即便如此,明智的做法是坚持使用久经考验的解决方案,而不是滥用 GC 功能自行开发。
  • 不要使用定稿!它是一种微妙的野兽,具有可怕的副作用,具有特定的用例和需求。不只是使用终结器来管理资源。
  • 您不能依赖finalize() 处理任何事情,更不用说依赖时间的操作了。它可能永远不会运行。

标签: java multithreading performance timer garbage-collection


【解决方案1】:

在我脑海中,使用finalize 可能出现的问题:

  • 调试地狱。您依赖于 GC 调用您的方法,您没有正确引用该对象等等等等。
  • 无法正确清理的几率增加,因为您使用 finalize() 创建资源和打开新连接,而不是关闭和清理它们。
  • GC 可能永远不会被调用,并且令牌永远不会被更新。
  • 获取新令牌时可能会发生异常,因此现在您在 GC 线程中抛出意外异常 -- 不希望。
  • 获取新令牌成功,但无论出于何种原因(例如网络速度较慢)都需要很长时间,因此您可能会收到java.lang.OutOfMemoryError: GC overhead limit exceeded

创建一个新线程是relatively inexpensive。当然,还有更好的方法,但我们在这里讨论的是 微秒。你说创建一个新线程“似乎很浪费”,但只要考虑一下替代方案,you already wasted more time than the overhead caused by creating a new thread every second for the next 40 years

使用计时器。

编辑:或者,更好的是,使用ScheduledExecutorService(参见 cmets)。

【讨论】:

  • 您可能想要补充一点,OP 应该考虑使用 ScheduledExecutorService 来获得它在这个特定用例中的相对优势(即请求中发生的异常) - stackoverflow.com/a/409993/3308999
猜你喜欢
  • 2013-09-20
  • 2015-07-07
  • 1970-01-01
  • 2016-02-19
  • 2012-03-13
  • 1970-01-01
  • 2023-04-10
  • 2012-09-25
相关资源
最近更新 更多