java - 单线程上下文中易失可变字段的风险?

标签 java clojure thread-safety clojure-java-interop

在单线程程序中使用 :volatile-mutable 限定符和 deftype 是否安全?这是 this question 的跟进, this one , 和 this one . (这是一个 Clojure 问题,但我添加了“Java”标签,因为 Java 程序员也可能对此有见解。)

我发现通过在 deftype 中使用 :volatile-mutable 字段而不是原子,我可以显着提高我正在处理的程序的性能,但我很担心,因为 deftype 的文档字符串说:

Note well that mutable fields are extremely difficult to use correctly, and are present only to facilitate the building of higher level constructs, such as Clojure's reference types, in Clojure itself. They are for experts only - if the semantics and implications of :volatile-mutable or :unsynchronized-mutable are not immediately apparent to you, you should not be using them.

事实上,:volatile-mutable 的语义和含义对我来说不是是显而易见的。

但是,Emerick、Carper 和 Grand 合着的 Clojure Programming 第 6 章说:

"Volatile" here has the same meaning as the volatile field modifier in Java: reads and writes are atomic and must be executed in program order; i.e., they cannot be reordered by the JIT compiler or by the CPU. Volatiles are thus unsurprising and thread-safe — but uncoordinated and still entirely open to race conditions.

这似乎意味着只要对单个易失可变 deftype 字段的访问全部发生在单个线程中,就没有什么特别需要担心的。 (没有什么特别,因为如果我可能使用惰性序列,我仍然必须小心处理状态的方式。)因此,如果没有任何东西将并行性引入我的 Clojure 程序,应该不会有特别的危险使用 deftype:volatile-mutable

这样对吗?我不了解哪些危险?

最佳答案

没错,很安全。您只需确保您的上下文确实是单线程的。有时要保证这一点并不容易。

在单线程上下文中使用 volatile 可变(或可变)字段时,在线程安全或原子性方面没有风险,因为只有一个线程,所以不可能有两个多个线程同时向该字段写入一个新值,或者一个线程根据过时的值写入一个新值。

正如其他人在评论中指出的那样,您可能只想使用 :unsynchronized-mutable 字段来避免 volatile 引入的成本。该成本来自这样一个事实,即每次写入都必须提交到主内存,而不是线程本地内存。参见 this answer有关这方面的更多信息。

与此同时,在单线程上下文中使用 volatile 不会有任何好处,因为不可能让一个线程写入一个新值,而其他线程读取同一字段时不会“看到”该值。 这就是 volatile 的用途,但它与单线程上下文无关。

另请注意,clojure 1.7 引入了 volatile!旨在提供一个“用于管理状态的 volatile 盒子”作为更快的替代方案 atom,具有类似的界面,但没有比较和交换语义。使用它时唯一的区别是调用 vswap!vreset! 而不是 swap!reset! .我会用那个代替 deftype 与 ^:volatile-mutable 如果我需要一个 volatile。

关于java - 单线程上下文中易失可变字段的风险?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30472496/

相关文章:

Java方法同步使用不当?

java - Eclipse 仅从测试文件夹加载 log4.properties

java - 使用 JDBC 模板并非所有变量绑定(bind)异常

Clojure JVM 7/8 改进

javascript - 如何在 Clojurescript 中循环 JavaScript 对象并将每个对象插入数组

java - SimpleDateFormat 似乎给出了错误的结果

c# - 跨线程的简单入队/出队是否需要 Queue.SyncRoot?

java - 使用 EndlessRecyclerOnScrollListener 的 Asynctask 的无尽 RecyclerView

java - 如果对支付处理器的 API 调用超过 60 秒则中断

c - 使用局部静态变量线程安全/可重入的函数