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