【问题标题】:Alternative to Java finalizerJava 终结器的替代方案
【发布时间】:2020-10-20 04:34:28
【问题描述】:

我正在使用 Mysql GET_LOCK 在分布式系统中实现锁定服务。在调用我的 getLock() 方法时,如果客户端获得了锁,我会在 DB 中创建一个条目,并在释放锁时删除该条目。

假设调用客户端将释放锁定一旦其目的服务。但是,我想确保在客户端不释放或未进行适当清理的情况下释放锁。

一种方法是在我的锁对象上使用 finalize 方法在调用 finalize 时释放它。然而它并不理想,增加了复杂性并且在 Java 9 中被弃用。我读到了 Phantom 引用,它比终结器更好,但它的复杂性也很高。我把它作为我最后的手段。

有没有更简单、更少依赖 JVM 的方法来处理这个用例?

【问题讨论】:

标签: java garbage-collection finalizer finalize phantom-reference


【解决方案1】:

不要这样做。问题大于好处。

无论您使用的是终结、参考 API 还是 Cleaner(使用参考 API),尝试使用对象的生命周期来控制锁都会产生更多问题。

无法保证对象会被垃圾回收。只要有足够的空闲堆内存,JVM 就没有理由让垃圾收集器运行。此外,即使垃圾收集器运行,也不能保证它会收集所有无法访问的对象。像 G1GC 这样的垃圾收集器专注于在给定的时间限制内尽可能多地回收内存,优先考虑对象年龄的影响。事实上,他们甚至不知道一个死物在周围躺了多久。

因此,当 JVM 对 GC 收集一堆较新的对象感到满意时,特定的不可访问对象可能会无限期地保持未被收集。

更糟糕的是,get garbage collected earlier than expected 的对象也有可能。对于显式锁定和解锁操作,这没有影响,因为程序的行为保持不变。但是,当您将对象的生命周期与解锁操作联系起来时,you’re in trouble。这尤其适用于对象只服务于锁定和解锁动作并且应用程序程序员忘记了解锁动作的情况,换句话说,锁定对象在执行锁定动作后完全未被使用。

为了防止提前收集,您需要Reference.reachabilityFence(lockObject) 之类的东西,但是当程序员忘记执行所需的解锁操作时,他们记住插入必要的可达性围栏的可能性有多大?他们更容易插入所需的解锁操作。

解决此问题的任何尝试都远非简单,同时仍无法提供值得付出努力的保证。你最好强烈提醒你的锁类的用户需要解锁它。考虑实现AutoCloseable 并在try-with-resource 块中使用它做广告。

【讨论】:

  • 感谢@holger 的详细解释。
猜你喜欢
  • 2015-11-27
  • 1970-01-01
  • 2012-05-02
  • 2012-07-26
  • 2013-03-10
  • 2013-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多