java - Java 是否保证当前同步的对象不会被垃圾回收?

标签 java garbage-collection java-memory-model

是否可以保证在线程持有监视器时对象不会被垃圾回收?

例如

class x {
    private WeakReference<Object> r;

    Object getMonitorObject() {
        Object o = new Object();
        r = new WeakReference<>(o);
        return o;
    }

    void thread1() throws Exception {
        synchronized (getMonitorObject()) {
            Thread.sleep(3000);
        }
    }

    void thread2() {
        Object b = r.get();
    }
}

具体来说,在这种情况下,如果在调用另一个线程时调用 thread2(),是否可以保证 b 将是非 nullthread1() 中 sleep ?我们假设整个 thread2() 被执行,而 thread1() 正在另一个线程中 hibernate 。

最佳答案

同步可以防止垃圾回收,但不是一般情况。在您的具体情况下,我们无法保证。

JLS §12.6.1 比较

Transformations of this sort may result in invocations of the finalize method occurring earlier than might be otherwise expected. In order to allow the user to prevent this, we enforce the notion that synchronization may keep the object alive. If an object's finalizer can result in synchronization on that object, then that object must be alive and considered reachable whenever a lock is held on it.

Note that this does not prevent synchronization elimination: synchronization only keeps an object alive if a finalizer might synchronize on it. Since the finalizer occurs in another thread, in many cases the synchronization could not be removed anyway.

因此,由于您的对象没有自定义终结器,因此在终结期间可能不会发生同步,原则上,您的对象是一个允许消除锁的临时对象,在这种情况下它不会阻止垃圾回收。

但是存在一个实际障碍,即您存储 WeakReference 的方式使得另一个线程可以在未收集对象时检索该对象,一旦存在这种可能性,该对象就不再是本地对象并锁定不能应用消除。

在构建之后立即积极收集对象(或完全消除它的存在)并在它逃逸之前清除弱引用或首先创建一个空的 WeakReference 的理论实现将在规范,因为在该执行场景中,锁消除是合理的。


请注意,即使您插入 reachabilityFence , 在调用 thread1() 的线程和调用 thread2() 的线程之间没有 happens-before 关系,因此第二个线程可能总是表现得好像在执行 thread2() 在另一个完成 synchronized block 或通过可达性栅栏之后,即使您的现实生活时钟另有说明。这是said explicitly Thread.sleep 没有同步语义。

关于java - Java 是否保证当前同步的对象不会被垃圾回收?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57872699/

相关文章:

Java 并发数 : is final field (initialized in constructor) thread-safe?

java - 第一次无法加载驱动程序类

java - 如何创建一个允许 NULL 值与 Hibernate 注释的唯一约束?

java - 匹配两个相同字符之间的字符串

c++ - 在 luabind::object 中存储一个带有父类的 lua 类

java - JVM 在何处保存有关引用和对象类型的信息

java - Dalvik 的内存模型和 Java 的一样吗?

java - 单击布局时如何选中复选框?

java - 调用 Calendar 类函数会产生 GC_CONCURRENT 消息

javascript - Javascript 中的事件处理程序、闭包和垃圾收集