[英]Can Locks be garbage collected while locked?
锁定时可以锁定垃圾(java.util.concurrent.locks.Lock)吗? 假设一个纯理论的例子:
WeakReference r;
public void foo(){
Lock lock = new ReentrantLock();
r = new WeakReference(lock);
lock.lock();
}
在foo()
执行后, lock
可以被垃圾收集? 换句话说, lock.lock()
创建lock.lock()
引用回锁? 你怎么知道的?
当锁定的Lock
无法再访问时,可以对其进行垃圾回收。 (JLS中“可达”的定义是: “可达对象是任何可以从任何活动线程继续计算中访问的对象。” - JLS 12.16.1)
但是, 某个线程正在等待的锁定Lock
必须执行Lock的lock / tryLock实例方法之一。 为此,线程必须具有对锁的引用; 即锁定方法当前正在访问的一个。 因此,某些线程试图获取的锁定锁是可达的,并且不能被垃圾收集。
换句话说,lock.lock()是否会创建任何强引用回锁?
在您的示例中,强引用以lock
变量的形式存在。 但是假设我们调整了你的例子以摆脱lock
; 例如
public void do_lock(WeakReference<ReentrantLock> r)
r.get().lock();
}
当你调用get()
,它将返回对ReentrantLock
对象的引用,该对象将保存在临时变量或寄存器中,使其可以很容易地访问。 只要lock()
调用正在运行,它将继续强烈可达。 当lock()
调用返回时, ReentrantLock
对象可能会再次变弱(可再次)。
你怎么知道的?
我怎么知道? 结合:
不需要使用全局队列来实现Lock
,因此没有理由对Lock
对象进行隐藏引用,以防止它无法访问。 此外, Lock
无法进行垃圾收集将成为存储泄漏,并且是一个主要的实现缺陷,我无法想象 Doug Lea等人犯了这个错误!
事实证明,虽然我们通常在概念上认为线程“获得”和“拥有”锁,但实际上并非从实现角度来看。 锁保持对拥有和等待线程的引用,而线程没有对锁的引用,并且不知道它们拥有的锁。
ReentrantLock实现也相当简单:没有静态的锁集合,并且没有跟踪锁的后台维护线程。
创建或锁定锁都不会在任何地方创建任何“隐藏的”新强引用,因此,在上面的示例中,一旦foo()
完成,就可以对lock
进行垃圾收集。
可以通过仔细阅读源代码来验证这一点:
http://fuseyism.com/classpath/doc/java/util/concurrent/locks/ReentrantLock-source.html
http://fuseyism.com/classpath/doc/java/util/concurrent/locks/AbstractQueuedSynchronizer-source.html
http://fuseyism.com/classpath/doc/java/util/concurrent/locks/AbstractOwnableSynchronizer-source.html
从技术上讲,唯一不能被垃圾收集的对象是bootstrap类加载器加载的类(其余是对前者的传出引用)
(java.util.concurrent.locks。)Lock(s)绝对是普通的对象,在垃圾收集方面与java.util.ArrayList没有什么不同。 我已经编写了具有LIFO语义的锁(或者特别是不是FIFO的AbstractQueueSynchronized),这对于最小化缓存未命中非常有用,因为最热门的线程可以开始工作。 点是绝对可以编写自己的自定义锁定/同步/原子代码。
假设你的意思是“在执行foo()
之后”,答案是肯定的 - 这确实是WeakReferences的重点。
你会知道,因为当你试图将转换WeakReference
r
回一个正常的(或强)引用,你会得到null
返回:
if (r.get() == null) {
// the lock was garbage collected
}
Lock与任何其他对象都没有什么不同。 这取决于某些内部Java机制是否引用了Lock。 但我认为Java没有理由保留对Lock的引用。
它可以在锁定时进行垃圾收集。 通过锁定不会创建强引用。 当然,在编写时,您必须将lock设置为null并运行gc以查看引用为null。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.