[英]Can Locks be garbage collected while locked?
Can Locks (java.util.concurrent.locks.Lock) be garbage collected while locked? 锁定时可以锁定垃圾(java.util.concurrent.locks.Lock)吗? Suppose a purely theoretical example:
假设一个纯理论的例子:
WeakReference r;
public void foo(){
Lock lock = new ReentrantLock();
r = new WeakReference(lock);
lock.lock();
}
Could lock
be garbage collected after foo()
gets executed? 在
foo()
执行后, lock
可以被垃圾收集? In other words, does lock.lock()
create any strong references back to the lock? 换句话说,
lock.lock()
创建lock.lock()
引用回锁? How do you know? 你怎么知道的?
A locked Lock
can be garbage collected when it is no longer reachable. 当锁定的
Lock
无法再访问时,可以对其进行垃圾回收。 (The definition of "reachable" in the JLS is: "A reachable object is any object that can be accessed in any potential continuing computation from any live thread." - JLS 12.16.1) (JLS中“可达”的定义是: “可达对象是任何可以从任何活动线程继续计算中访问的对象。” - JLS 12.16.1)
However, a locked Lock
that some thread is waiting on must be executing one of the Lock's lock / tryLock instance methods. 但是, 某个线程正在等待的锁定
Lock
必须执行Lock的lock / tryLock实例方法之一。 For this to happen, the thread must have a reference to the lock; 为此,线程必须具有对锁的引用; ie one that the lock method is currently accessing.
即锁定方法当前正在访问的一个。 Therefore, a locked Lock that some thread is trying to acquire is reachable, and cannot be garbage collected.
因此,某些线程试图获取的锁定锁是可达的,并且不能被垃圾收集。
In other words, does lock.lock() create any strong references back to the lock?
换句话说,lock.lock()是否会创建任何强引用回锁?
No. In your example, the strong reference exists in the form of the lock
variable. 在您的示例中,强引用以
lock
变量的形式存在。 But suppose that we tweaked your example to get rid of lock
; 但是假设我们调整了你的例子以摆脱
lock
; eg 例如
public void do_lock(WeakReference<ReentrantLock> r)
r.get().lock();
}
When you call get()
, it will return a reference to the ReentrantLock
object which will be held in a temporary variable or register, making it strongly reachable. 当你调用
get()
,它将返回对ReentrantLock
对象的引用,该对象将保存在临时变量或寄存器中,使其可以很容易地访问。 It will continue to be strongly reachable as long as the lock()
call is running. 只要
lock()
调用正在运行,它将继续强烈可达。 When the lock()
call returns, the ReentrantLock
object may become weakly reachable (again). 当
lock()
调用返回时, ReentrantLock
对象可能会再次变弱(可再次)。
How do you know?
你怎么知道的?
How do I know? 我怎么知道? A combination of:
结合:
There is not need to implement Lock
using global queues, and hence no reason to have a hidden reference to the Lock
object that would prevent it becoming unreachable. 不需要使用全局队列来实现
Lock
,因此没有理由对Lock
对象进行隐藏引用,以防止它无法访问。 Furthermore, a Lock
that could not be garbage collected when it was locked would be a storage leak, and a major implementation flaw, and I cannot imagine Doug Lea et al making that mistake! 此外,
Lock
无法进行垃圾收集将成为存储泄漏,并且是一个主要的实现缺陷,我无法想象 Doug Lea等人犯了这个错误!
It turns out that while we often conceptually think that threads 'obtain' and 'own' locks, it's actually not the case from the implementation perspective. 事实证明,虽然我们通常在概念上认为线程“获得”和“拥有”锁,但实际上并非从实现角度来看。 The locks keep references to owning and waiting threads, while the threads have no references to locks, and have no knowledge of the locks they 'own'.
锁保持对拥有和等待线程的引用,而线程没有对锁的引用,并且不知道它们拥有的锁。
The ReentrantLock implementation is also rather straightforward: there are no static collections of locks, and there are no background maintenance threads that keep track of locks. ReentrantLock实现也相当简单:没有静态的锁集合,并且没有跟踪锁的后台维护线程。
Neither creating, nor locking a lock creates any 'hidden' new strong references anywhere, so, in the example above, the lock
can be garbage collected once foo()
is done. 创建或锁定锁都不会在任何地方创建任何“隐藏的”新强引用,因此,在上面的示例中,一旦
foo()
完成,就可以对lock
进行垃圾收集。
One can verify this by perusing the source code: 可以通过仔细阅读源代码来验证这一点:
http://fuseyism.com/classpath/doc/java/util/concurrent/locks/ReentrantLock-source.html 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/AbstractQueuedSynchronizer-source.html
http://fuseyism.com/classpath/doc/java/util/concurrent/locks/AbstractOwnableSynchronizer-source.html http://fuseyism.com/classpath/doc/java/util/concurrent/locks/AbstractOwnableSynchronizer-source.html
Technically, the only objects that cannot be garbage collected are the classes loaded by the bootstrap classloader (the rest are outgoing references to the former) 从技术上讲,唯一不能被垃圾收集的对象是bootstrap类加载器加载的类(其余是对前者的传出引用)
(java.util.concurrent.locks.)Lock(s) are absolutely normal objects, not different than java.util.ArrayList in terms of garbage collection. (java.util.concurrent.locks。)Lock(s)绝对是普通的对象,在垃圾收集方面与java.util.ArrayList没有什么不同。 I have written locks w/ LIFO semantics (or specifically AbstractQueueSynchronized that is not FIFO), that's useful to minimized cache misses since the hottest threads get to work even more.
我已经编写了具有LIFO语义的锁(或者特别是不是FIFO的AbstractQueueSynchronized),这对于最小化缓存未命中非常有用,因为最热门的线程可以开始工作。 Point is that is absolutely possible to write your own custom locking/sync/atomic code.
点是绝对可以编写自己的自定义锁定/同步/原子代码。
Assuming that you mean "after foo()
gets executed", the answer is yes - that's really the point of WeakReferences. 假设你的意思是“在执行
foo()
之后”,答案是肯定的 - 这确实是WeakReferences的重点。
You would know that because when you tried to convert the WeakReference
r
back into a regular (or strong) reference, you'd get null
returned: 你会知道,因为当你试图将转换
WeakReference
r
回一个正常的(或强)引用,你会得到null
返回:
if (r.get() == null) {
// the lock was garbage collected
}
The Lock is not unlike any other object. Lock与任何其他对象都没有什么不同。 It depends if some internal Java mechanism references the Lock.
这取决于某些内部Java机制是否引用了Lock。 But I see no reason why Java should keep a reference to the Lock.
但我认为Java没有理由保留对Lock的引用。
It can be garbage collected while locked. 它可以在锁定时进行垃圾收集。 No strong reference is created by taking the lock.
通过锁定不会创建强引用。 As written, of course, you'd have to set lock to null and run the gc to see the reference go null.
当然,在编写时,您必须将lock设置为null并运行gc以查看引用为null。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.