java - java.lang.ref.Reference 方法的内存语义

标签 java concurrency reference volatile consistency

我正在开发一些处理引用对象的并发算法。我正在使用 Java 17。

问题是我不知道 get、clear 或 refersTo 等操作的内存语义是什么。它没有记录在 Javadoc 中。

查看OpenJdk的源代码,referent没有修饰符,比如volatile(而引用队列的next指针是volatile)。 此外,get 实现是微不足道的,但它是一个内在的候选者。 clear 和 refersTo 是原生的。所以我不知道他们到底在做什么。

当 GC 清除引用时,我必须假设所有线程都会看到它被清除,否则它们会看到对对象(正在处理中)的引用被垃圾收集,但这只是一个非正式的猜测。

所有这些操作的内存语义是否有任何保证?

如果没有,是否有办法通过在调用其中一个操作之前和/或之后调用例如栅栏操作来获得对 volatile 访问的相同保证?

最佳答案

当您调用 clear() 时在引用对象上,它只会清除这个特定的 Reference对象对应用程序的其余部分没有任何影响,也没有特殊的内存语义。就像您在代码中看到的一样,赋值 null。到没有 volatile 的字段修饰符。

心灵the documentation of clear() :

This method is invoked only by Java code; when the garbage collector clears references it does so directly, without invoking this method.

因此这与 GC 清除引用的事件无关。当 GC 清除引用时,您的假设“所有线程都会看到它被清除”是正确的。 documentation of WeakReference 状态:

Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable. At that time it will atomically clear all weak references to that object and all weak references to any other weakly-reachable objects from which that object is reachable through a chain of strong and soft references.

所以在这一点上,不仅所有的线程都会同意一个弱引用已经被清除,它们也会同意对同一个对象的所有弱引用都已经被清除。可以在 SoftReference 找到类似的声明。和 PhantomReference .

The Java Language Specification, §12.6.2. Interaction with the Memory Model将可能发生此类原子清除的点称为可达性决策点。它根据“先于 di”和“后于 ”关系指定这些点与其他程序操作之间的交互,最重要的是:

If r is a read that sees a write w and r comes-before di, then w must come-before di.

If x and y are synchronization actions on the same variable or monitor such that so(x, y) (§17.4.4) and y comes-before di, then x must come-before di.

因此,GC 操作将被插入到同步顺序中,即使是快速读取也无法破坏它,但重要的是要记住,应用程序不知道可达性决策点的确切位置。很明显,它介于最后一点 get() 之间。返回了一个非 null引用或 refersTo(null)返回 false第一点 get()返回 nullrefersTo(null)返回 true .

对于实际应用,一旦引用报告对象被垃圾回收,您就可以确定它不会再出现在任何地方¹,这一事实就足够了。只需将引用对象保密,以确保没有人调用 clear()在上面。

¹ 抛开“终结器复活”之类的事情

关于java - java.lang.ref.Reference 方法的内存语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71255376/

相关文章:

java - 不要将 Maven 目标和选项命令打印到 Jenkins 中的控制台输出

java - 从用户 java 读取一行文本

mysql - 即使在使用连接池后如何处理过多的并发连接?

java - 代码产生并发修改异常

C#,MySQL 对象引用未设置为对象实例错误

C# 从另一个类引用文本框

java - 将带有映射的对象列表转换为基元数组

java - 超出最大游标数 SQLException-- 配置问题或游标泄漏?

java - 引用分配是原子的,所以为什么要使用 AtomicReference

用于通过 ZMQ 套接字发送对象的 ZeroMQ 的 Java "Reference"解决方法