简体   繁体   English

锁可以锁定垃圾吗?

[英]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: 结合:

  • knowledge of the Java Language Specification's definition of reachability and other things, 了解Java语言规范对可达性和其他事物的定义,
  • experience with implementing JVMs, 实现JVM的经验,
  • good old-fashioned logic, and ... 良好的老式逻辑,......
  • I confirmed it by reading the OpenJDK source code (though this doesn't prove anything about JVMs in general.) 我通过阅读OpenJDK源代码确认了这一点(尽管这并不能证明 JVM的一般性。)

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.

相关问题 用作垃圾回收的同步锁的对象数组 - Array of Objects to be used as Synchronization locks being garbage collected Singleton object 中的包装器变量能否在 Singleton 不是 Z37A6259CC0C1DAE299A7866648 时收集垃圾? - Can a wrapper variable within a Singleton object get garbage collected while Singleton is not null? 如果我用对象字段填充列表,那么当列表仍在作用域内时,是否可以对我的对象进行垃圾回收? - If I populate a list with object fields, can my object be garbage collected while the list remains in scope? 嵌套静态类的变量可以被垃圾回收吗? - Can variable of nested static class be garbage collected? OutOfMemoryError - 为什么等待的Thread不能被垃圾收集? - OutOfMemoryError - why can a waiting Thread not be garbage collected? 可以将JVM的方法区域垃圾收集? - can method area of JVM be garbage collected? 如何找出JVM上次收集垃圾的时间? - How can I find out the time the JVM last garbage collected? 在什么行可以将此对象视为垃圾回收。 爪哇 - At what line can this object be considered to be garbage collected. Java 如果父类不是,那么java 8方法引用是否可以被垃圾收集? - Can a java 8 method reference be garbage collected if the parent class isn't? java字符串文字可以被垃圾收集吗?如果是,如何证明? - Can java string literals be garbage collected?. If Yes, how to prove it?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM