锁可以锁定垃圾吗?

时间:2010-12-28 00:16:35

标签: java multithreading concurrency locking thread-safety

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()是否会创建任何强引用回锁? 你怎么知道的?

6 个答案:

答案 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对象可能变得无法访问(再次)。

  

你怎么知道?

我怎么知道?结合:

  • 了解Java语言规范对可达性和其他事物的定义,
  • 实施JVM的经验,
  • 良好的老式逻辑,......
  • 我通过阅读OpenJDK源代码确认了这一点(虽然这并不是证明关于JVM的任何内容。)

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