有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java锁可以在锁定时进行垃圾收集吗?

锁(java.util.concurrent.Locks.Lock)是否可以在锁定时进行垃圾收集? 假设一个纯理论的例子:

WeakReference r;

public void foo(){
       Lock lock = new ReentrantLock();
       r = new WeakReference(lock);   
       lock.lock();
}

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


共 (6) 个答案

  1. # 1 楼答案

    当锁定的Lock不再可访问时,可以对其进行垃圾回收。(JLS中“可访问”的定义是:“可访问对象是可以从任何活动线程在任何潜在的连续计算中访问的任何对象。”-JLS 12.16.1)

    但是,某个线程正在等待的被锁定的Lock必须执行锁的Lock/tryLock实例方法之一。要实现这一点,线程必须具有对锁的引用;i、 e.锁定方法当前正在访问的对象。因此,某个线程试图获取的锁定锁是可访问的,不能被垃圾回收

    In other words, does lock.lock() create any strong references back to the lock?

    否。在您的示例中,强引用以lock变量的形式存在。但是假设我们调整了您的示例以除去lock;e、 g

    public void do_lock(WeakReference<ReentrantLock> r) 
       r.get().lock();
    }
    

    调用get()时,它将返回对ReentrantLock对象的引用,该对象将保存在临时变量或寄存器中,从而使其具有强可访问性。只要lock()调用正在运行,它将继续是强可访问的。当lock()调用返回时,ReentrantLock对象可能变得弱可及(再次)

    How do you know?

    我怎么知道?以下各项的组合:

    • 了解Java语言规范对可达性和其他方面的定义
    • 具有实施JVM的经验
    • 好的老式逻辑,还有
    • 我通过阅读OpenJDK源代码证实了这一点(尽管这并不能证明JVM的任何一般性)

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

  2. # 2 楼答案

    假设你的意思是“在foo()被执行之后”,答案是肯定的——这确实是weakreference的重点

    您应该知道,因为当您尝试将WeakReference{}转换回常规(或强)引用时,会返回null

    if (r.get() == null) {
        // the lock was garbage collected
    }
    
  3. # 3 楼答案

    从技术上讲,唯一不能被垃圾收集的对象是引导类加载器加载的类(其余的是对前者的传出引用)

    (java.util.concurrent.locks)锁是绝对正常的对象,与java没有区别。util。ArrayList在垃圾收集方面的作用。我已经编写了带有后进先出语义的锁(或者特别是非FIFO的锁),这对于最小化缓存未命中非常有用,因为最热的线程可以工作得更多。关键是,完全可以编写自己的自定义锁定/同步/原子代码

  4. # 4 楼答案

    事实证明,虽然我们通常在概念上认为线程“获取”和“拥有”锁,但从实现的角度来看,事实并非如此。锁保留对拥有和等待线程的引用,而线程没有对锁的引用,也不知道它们“拥有”的锁

    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

  5. # 5 楼答案

    它可以在锁定时进行垃圾收集。获取锁不会创建强引用。当然,正如所写的,您必须将lock设置为null并运行gc以查看引用变为null

  6. # 6 楼答案

    锁与任何其他对象都不一样。这取决于内部Java机制是否引用了锁。但是我看不出Java为什么要保留对锁的引用