锁可以锁定垃圾吗?

Ole*_*boy 14 java concurrency multithreading locking thread-safety

锁定时可以锁定垃圾(java.util.concurrent.locks.Lock)吗?假设一个纯理论的例子:

WeakReference r;

public void foo(){
       Lock lock = new ReentrantLock();
       r = new WeakReference(lock);   
       lock.lock();
}
Run Code Online (Sandbox Code Playgroud)

被执行lock后可能被垃圾收集foo()?换句话说,是否会lock.lock()创建任何强大的引用回锁?你怎么知道的?

Ste*_*n C 20

锁定时Lock可以在无法访问时进行垃圾回收.(JLS中"可达"的定义是:"可到达对象是任何可以从任何活动线程继续计算中访问的对象." - JLS 12.16.1)

但是,锁定的Lock一些线程在等待上必须执行的锁的锁/的tryLock实例方法之一.为此,线程必须具有对锁的引用; 即锁定方法当前正在访问的一个.因此,某些线程试图获取的锁定锁是可达的,并且不能被垃圾收集.

换句话说,lock.lock()是否会创建任何强引用回锁?

在您的示例中,强引用以lock变量的形式存在.但是假设我们调整了你的例子来摆脱lock; 例如

public void do_lock(WeakReference<ReentrantLock> r) 
   r.get().lock();
}
Run Code Online (Sandbox Code Playgroud)

当您调用时get(),它将返回ReentrantLock对象的引用,该对象将保存在临时变量或寄存器中,使其可以很容易地访问.只要lock()呼叫正在运行,它将继续强烈可达.当lock()调用返回时,ReentrantLock对象可能变得弱可达(再次).

你怎么知道的?

我怎么知道?结合:

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

不需要Lock使用全局队列来实现,因此没有理由对该Lock对象进行隐藏引用以防止它变得无法访问.此外,Lock当它被锁定时无法收集垃圾将是存储泄漏,并且是一个主要的实现缺陷,我无法想象 Doug Lea等人犯了这个错误!