当我注意到一个可变字段用^:unsynchronized-mutable注释时,我正在研究一个clojure lib。 Mutable是可变的,但我不知道 unynchronized 部分是什么意思,所以我读了docs,其中包含:
请注意,可变字段非常难以使用 正确地,并且仅用于促进更高层的建设 Clojure中的级别构造,例如Clojure的引用类型 本身。它们仅供专家使用 - 如果语义和含义 of:volatile-mutable或:unsynchronized-mutable不是立即的 很明显,你不应该使用它们。
我无法得到细微差别:它是否说在实践中我选择哪个可变性注释无关紧要,或者人们应该忘记完全使用可变类型?
而且,为了好奇,在较低的抽象层次中,它们之间的语义差异是什么?
谢谢!
答案 0 :(得分:2)
嗯,并不是说“人”应该忘记使用可变类型。它说任何使用它们的人都应该知道不同步和易失性之间的区别(并暗示这不是特定于Clojure的问题,否则它将在文档字符串中解释)。我不知道一个明确的解释,但在使用Clojure的可变deftype字段之前,你应该理解java内存模型,以及一般的线程和同步。
我手边没有明确的参考资料,但维基百科似乎对该主题有一个useful article(我刚刚发现它,并且只是略去了它)。
答案 1 :(得分:2)
这些是java构造,这就是为什么你不会在clojure文档中的任何地方看到它们被引用,除了'不要使用它'。
对于声明为'volatile'的所有变量,读取和写入都是原子的。
非同步字段是常规Java可变字段。
请参阅https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html
实际上,这意味着,如果您有数据结构,当多个线程访问数据以进行读取或写入 volatile 时,目标将始终保持一致;也就是说,您将始终在对该数据进行操作之前或之后完全获得数据对象。
如果这不是100%有道理,我很抱歉;语义是复杂的;如果您想要更深入的了解,请阅读此内容:When exactly do you use the volatile keyword in Java?
tldr;
挥发性比不同步的性能稍差;但它提供了更好的跨线程数据保证。
如果可以,请避免使用它们,但如果您需要使用它们,则可能需要:volatile-mutable
答案 2 :(得分:1)
如果你不理解:volatile-mutable
和:unsynchronized-mutable
之间的区别,你应该使用Clojure的引用类型,而不是直接使用可变字段。
这两种可变性具有不同的策略来保证共享可变数据的线程之间的一致性,这导致读/写操作的不同性能。有时,通过微调使用特定类型的可变性,您可以获得更好的性能。如果你天真地使用它们,你会变得奇怪而难以理解。