繁体   English   中英

锁可以锁定垃圾吗?

[英]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对象可能会再次变弱(可再次)。

你怎么知道的?

我怎么知道? 结合:

  • 了解Java语言规范对可达性和其他事物的定义,
  • 实现JVM的经验,
  • 良好的老式逻辑,......
  • 我通过阅读OpenJDK源代码确认了这一点(尽管这并不能证明 JVM的一般性。)

不需要使用全局队列来实现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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM