单线程上下文中volatile-mutable字段的风险?

时间:2015-05-27 03:12:57

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

在单线程程序中将:volatile-mutable限定符与deftype一起使用是否安全?这是this questionthis onethis one的后续行动。 (这是一个Clojure问题,但我添加了#34; Java"标签,因为Java程序员也可能对它有洞察力。)

我发现,通过使用:volatile-mutable中的deftype字段而不是原子,我可以在我正在制作的程序中获得显着的性能提升,但我&#39因为deftype的文档字符串说:

,我很担心
  

请注意,可变字段非常难以使用   正确地,并且仅用于促进更高层的建设   Clojure中的级别构造,例如Clojure的引用类型   本身。它们仅供专家使用 - 如果语义和含义   of:volatile-mutable或:unsynchronized-mutable不是立即的   很明显,你不应该使用它们。

事实上,:volatile-mutable的语义和含义对我来说并非

然而,Emerick,Carper和Grand的 Clojure Programming 第6章说:

  

"挥发性"这里的含义与volatile中的volatile字段修饰符相同   Java:读取和写入都是原子的,必须在中执行   程序顺序;即,它们不能由JIT编译器重新排序或   由CPU。因此,挥发性物质并不令人惊讶,而且是线程安全的 - 但是   不协调,仍然完全对竞争条件开放。

这似乎意味着只要访问单个volatile-mutable deftype字段都发生在一个线程中,就没有什么特别值得担心的了。 (没有什么特殊,因为如果我可能使用延迟序列,我仍然要小心处理状态。)因此,如果没有任何东西将并行性引入我的Clojure程序,那么应该没有特别的危险将deftype:volatile-mutable一起使用。

这是对的吗?我不明白有什么危险?

1 个答案:

答案 0 :(得分:3)

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

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

正如其他人在评论中指出的那样,您可能只想使用:unsynchronized-mutable字段来避免volatile引入的成本。这个成本来自于每个写入必须提交到主内存而不是线程本地内存。有关详细信息,请参阅this answer

同时,在单线程上下文中使用volatile,你什么也得不到,因为没有机会让一个线程写一个新的值,而不会被看到""通过其他线程读取相同的字段。 这就是volatile的用途,但它在单线程环境中无关紧要。

另请注意,clojure 1.7引入了volatile!旨在提供一个用于管理状态"的易失性框。作为更快的替代品 atom ,具有类似的接口,但没有它的比较和交换语义。使用它时唯一的区别是您拨打vswap!vreset!而不是swap!reset!。我会用它代替 如果我需要一个易失性,请使用^:volatile-mutable进行deftype。